QT学习记录

学习进度

week3:
QStringListModel(modelview类)。model更新时自动更新view。
图片.png

mylistview.h

#ifndef MYLISTVIEW_H
#define MYLISTVIEW_H

#include<QWidget>
#include<QStringListModel>
#include<QListView>
#include<QHBoxLayout>
#include<QPushButton>
#include<QLineEdit>
#include<QModelIndex>
#include<QMessageBox>
#include<QInputDialog>
class MyListView : public QWidget
{
    Q_OBJECT

public:
    MyListView();
private:
    QStringListModel *model;
    QListView *listView;
private slots:
    void insertData();
    void deleteData();
    void showData();
};
#endif // MAINWINDOW_H

mylistview.cpp

#include "mylistview.h"

MyListView::MyListView()
{
    model=new QStringListModel(this);//创建model对象
    QStringList data;//设置model数据
    data<<"Letter A"<<"Letter B"<<"Letter C";
    model->setStringList(data);//把数据设置为model的数据
    listView=new QListView(this);
    listView->setModel(model);//view和model绑定

    QHBoxLayout *btnLayout=new QHBoxLayout;
    QPushButton *insertBtn=new QPushButton(tr("insert"),this);
    QPushButton *delBtn=new QPushButton(tr("delete"),this);
    QPushButton *showBtn=new QPushButton(tr("show"),this);
    btnLayout->addWidget(insertBtn);
    btnLayout->addWidget(delBtn);
    btnLayout->addWidget(showBtn);//添加下方按钮

    QVBoxLayout *mainLayout=new QVBoxLayout(this);
    mainLayout->addWidget(listView);
    mainLayout->addLayout(btnLayout);
    this->setLayout(mainLayout);//全局

    connect(insertBtn,SIGNAL(clicked()),this,SLOT(insertData()));
    connect(delBtn,SIGNAL(clicked()),this,SLOT(deleteData()));
    connect(showBtn,SIGNAL(clicked()),this,SLOT(showData()));
}

void MyListView::insertData()
{
    bool isOK;
    QString text=QInputDialog::getText(NULL,"Insert","Please input new data",QLineEdit::Normal,"you are inserting new data",&isOK);
    if(isOK)
    {
        int row=listView->currentIndex().row();
        model->insertRows(row,1);
        QModelIndex index=model->index(row);
        model->setData(index,text);
        listView->setCurrentIndex(index);
        listView->edit(index);
    }
}

void MyListView::deleteData()

{
    if(model->rowCount()>1)
    {
        model->removeRows(listView->currentIndex().row(),1);//1是在当前行插入的行数
    }
}

void MyListView::showData()
{
    QStringList data=model->stringList();
    QString str;
    foreach(QString s,data)
    {
        str+=s+"\n";
    }
    QMessageBox::information(this,"DATA",str);
}

main.cpp

#include "mylistview.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MyListView w;
    w.show();
    return a.exec();
}

QTreeWidget(item class)
图片.png

main.cpp

#include "treewidget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    TreeWidget w;

    w.show();
    return a.exec();
}

treewidget.cpp

#include "treewidget.h"


TreeWidget::TreeWidget()
{
    tree=new QTreeWidget(this);
    tree->setColumnCount(2);//columnCount是用来在列表中显示树的
    QTreeWidgetItem *root=new QTreeWidgetItem(tree,QStringList(QString("Root")));
    QTreeWidgetItem *leaf=new QTreeWidgetItem(root,QStringList(QString("Leaf 1")));
    root->addChild(leaf);
    QTreeWidgetItem *leaf2=new QTreeWidgetItem(root,QStringList(QString("Leaf 1")));
    leaf2->setCheckState(0,Qt::Checked);
    root->addChild(leaf2);
    QList<QTreeWidgetItem *>rootList;
    rootList<<root;
    tree->insertTopLevelItems(0,rootList);
}

treewidget.h

#ifndef TREEWIDGET_H
#define TREEWIDGET_H

#include<QMainWindow>
#include<QWidget>
#include<QTreeWidget>

class TreeWidget : public QWidget
{
public:
     TreeWidget();
private:
      QTreeWidget *tree;
};
#endif // TREEWIDGET_H

QListWidget(itemclass)
图片.png

main.cpp


#include <QApplication>
#include<QWidget>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    ListWidget lw;
    lw.resize(400,200);
    lw.show();
    return a.exec();
}

listWidget.cpp

#include "listWidget.h"

ListWidget::ListWidget()
{
    label=new QLabel;
    label->setFixedWidth(70);
    list=new QListWidget;
    list->addItem(tr("line"));
    list->addItem(tr("Rect"));
    list->addItem(tr("Oval"));
    list->addItem(tr("Triangle"));
    QHBoxLayout *layout=new QHBoxLayout;
    layout->addWidget(label);
    layout->addWidget(list);
    setLayout(layout);
    connect(list,SIGNAL(currentTextChanged(QString)),label,SLOT(setText(QString)));
}

listWidget.h

#ifndef LISTWIDGET_H
#define LISTWIDGET_H

#include <QWidget>
#include<QLabel>
#include<QListWidget>
#include<QHBoxLayout>


class ListWidget : public QWidget
{
public:
      ListWidget();
private:
      QLabel *label;
      QListWidget *list;
};
#endif // LISTWIDGET_H

Qt model-view

不降低性能的前提下处理大量数据,可以让一个model注册给多个view。少量数据时用item view类。分别是QList(\Table\Tree)Widget。较大数据使用QList(\Table\Tree)view,且需要提供
model。
对接

关联存储器

存储二元组映射。QMap<K,T>是key-value数据结构,按k升序进行存储。可用insert或[]插入

QMap<QString,int>map;
map.insert("test1",1);
map.insert("test2",2);
//或
map["test1"]=1;

而取值时,在非const的map中,[]取不存在的key值会自动创建一个值为空的key。为避免这种查询时自动插入,可使用:c++map.value(key);
key不存在时会返回0,对象类型则会调用默认构造函数,返回一个对象,不创建新的键值对。如果需要不存在的键返回默认值,可使用c++int seconds = map.value("delay", 30);
QMultiMap一个key索引多个值。
QHash<K,T>查找速度更快,存储不排序,K类型需被qHash()支持。可用reverse()函数扩大散列,squeeze()压缩
遍历方式:

//【Java风格】next()和previous()函数可以返回一个键值对,而不仅仅是值
QMap<QString,int> map;//创建QMap对象map
QMapIterator<QString,int>i(map)//创建map的迭代器i
while(i.hasNext()) sum+=i.next().value();
//Mutable遍历器可以修改key对应的值,如
i.setValue(-i.value());
//【stl风格】,foreach循环分别对key和value循环
QMultiMap<QString,int>map;
foreach(QString key,map.keys())
{
      foreach(int value,map.values(key))
  {
    dosth(key,value);
  }
}
遍历器

每个容器都有对应的遍历器。
只读遍历器有:QVectorIterator,QLinkedListIterator和 QListIterator三种;读写遍历器同样也有三种,只不过名字中具有一个 Mutable,即QMutableVectorIterator,QMutableLinkedListIterator和 QMutableListIterator。
对list或者vector使用at()进行只读访问([]既可以是左值也可以是右值,而at不能作为左值)
尽量使用const_iterator,constBegin(),constEnd(),不然在数据改变时Qt会进行深复制。
【Java风格遍历器】
Java风格的遍历器不指向元素,而是指向元素间隙。

//从前向后
QList<double>list;
QListIterator<double>i(list);
while(i.hasNext()){doSomethingWith(i.next());}
//从后向前。toBack()指向最后一个元素的后面的位置,用hasPrevious()和previous()函数遍历。

【STL遍历器】
每个顺序容器类都有俩遍历器:C::iterator和C::const_iterator。后者不允许对数据修改。begin和end分别指向第一个和最后一个之后的元素。容器为空时begin和end相同(或用isEmpty判断是否为空)。
可以用++--使遍历器移动,返回值是指向这个元素的指针。

QList<double>::iterator i=list.begin();
while(i!=list.end())
{
  *i=qAbs(*i);++i;
}

如果要使用 STL 风格的遍历器,并且要遍历作为返回值的容器,就要先创建返回值的拷贝,然后进行遍历(java不用,因为会自动创建拷贝)。
可以通过传入引用避免对容器的拷贝工作,防止临时拷贝占用大量内存。

顺序存储容器

1.QVector:知道自己长度并且可以改变大小的数组。如果没有显式赋值则自动初始化为0

QVector<double> v(length);
v[pos]=value;//用[]赋值
QVector<double> v;
v.append(value1);
v.append(value1);
QVecor<double>v;//不知道长度,通过append添加
//或使用被重载的<<
v<<value1<<value2;

2.QLinkedList:双向链表。添加只能用<<和append()
3.QList:除非我们需要进行在很大的集合的中间位置的添加、删除操作,或者是需要所有元素在内存中必须连续存储,否则我们应该一直使用 Qlist。QStringList用来操作QString,QStack和QQueue则是数据结构中的堆栈队列。
4.模板类的占位符除了基本数据类型也可以是指针或者类,如果是类的话需要提供默认构造函数、拷贝构造函数和赋值操作符,QObject的子类不符合条件,但是可以通过存储QObject的指针而不是值实现。也可以容器的容器

QList<QVector<int> > list;//》\>之间的空格不能省略,防止编译器把它解析成>>操作符 
week2:
QWidget
Qt Graphics View Framework

Qtpainter是状态机,Graphics View是面向对象的。支持对model对象不同角度的观察。
line.h

#ifndef LINE_H
#define LINE_H

#include "shape.h"
class Line:public Shape
{
public:
     Line();//构造函数
     void paint(QPainter &painter);//父类的虚函数,需重写
};
#endif // LINE_H

rect.h

#ifndef RECT_H
#define RECT_H
#include "shape.h"
class Rect:public Shape
{
public:
        Rect();
        void paint(QPainter &painter);
};
#endif // RECT_H

shape.h

#ifndef SHAPE_H
#define SHAPE_H
#include<QtWidgets>
class Shape
{
public:
        enum Code//枚举,变量范围不超过列举的类型
        {
            Line,
            Rect
        };
        Shape();
        void setStart(QPoint s){start=s;}
        void setEnd(QPoint e){end=e;}
        QPoint startPoint() {return start;}
        QPoint endPoint() {return end;}
        void virtual paint(QPainter & painter)=0;
   protected:
        QPoint start;
        QPoint end;
};



#endif // SHAPE_H

paintwidget.h

#ifndef PAINTWIDGET_H
#define PAINTWIDGET_H

#include<QtWidgets>
#include<QDebug>
#include"shape.h"
#include"line.h"
#include"rect.h"
class PaintWidget : public QWidget
{
    Q_OBJECT
public:
    PaintWidget(QWidget *parent=0);
public slots:
    void setCurrentShape(Shape::Code s)
    {
        if(s!=currShapeCode)
        {
            currShapeCode=s;
        }
    }//if 防止递归
protected:
    void paintEvent(QPaintEvent *event);
    void mousePressEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);
private:
    Shape::Code currShapeCode;
    Shape *shape;
    bool perm;//用来判断一次绘图是否结束
    QList<Shape*>shapeList;//图形序列
};
#endif // PAINTWIDGET_H

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include<QtGui>
#include<QAction>
#include<QLabel>
#include<QToolBar>
#include<QLabel>
#include<QWidget>
#include<QStatusBar>
#include<QActionGroup>
#include "shape.h"
#include "paintwidget.h"
class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = 0);
signals:
    void changeCurrentShape(Shape::Code newShape);
private slots:
    void drawLineActionTriggered();
    void drawRectActionTriggered();
};
#endif // MAINWINDOW_H

line.cpp

#include "line.h"
Line::Line()
{

}
void Line::paint(QPainter &painter)
{
    painter.drawLine(start,end);
}//重写的paint函数

rect.cpp

#include "rect.h"
Rect::Rect()
{

}
void Rect::paint(QPainter &painter)
{
    painter.drawRect(start.x(),start.y(),end.x()-start.x(),end.y()-start.y());
}

shape.cpp

#include "shape.h"
Shape::Shape()
{

}

paintwidget.cpp

#include "paintwidget.h"

PaintWidget::PaintWidget(QWidget *parent)
    :QWidget(parent),currShapeCode(Shape::Line),shape(NULL),perm(false)
{
    setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
}
void PaintWidget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.setBrush(Qt::white);
    painter.drawRect(0,0,size().width(),size().height());
    foreach(Shape * shape,shapeList)
    {
        shape->paint(painter);
    }
    if(shape)
    {
        shape->paint(painter);
    }
}

void PaintWidget::mousePressEvent(QMouseEvent *event)
{
    switch(currShapeCode)
    {
    case Shape::Line:
        {
            shape=new Line;
            break;
        }
    case Shape::Rect:
        {
            shape=new Rect;
            break;
        }
    }
    if(shape!=NULL)
    {
        perm=false;
        shapeList<<shape;
        shape->setStart(event->pos());
        shape->setEnd(event->pos());
    }
}

//首先我们需要按下鼠标,确定直线的第一个点,所以在 mousePressEvent 里面,
//我们让 shape 保存下 start 点。然后在鼠标按下的状态下移动鼠标,此时,直线就会发生变化
//实际上是直线的终止点在随着鼠标移动,所以在 mouseMoveEvent 中我们让 shape 保存下 end 点
//然后调用 update()函数,这个函数会自动调用 paintEvent()函数,显示出我们绘制的内容。
//最后,当鼠标松开时,图形绘制完毕,我们将一个标志位置为 true,此时说明这个图形绘制完毕。
void PaintWidget::mouseMoveEvent(QMouseEvent *event)
{
    if(shape &&!perm)
    {
        shape->setEnd(event->pos());
        update();
    }
}

void PaintWidget::mouseReleaseEvent(QMouseEvent *event)
{
    perm=true;
}

mainwindow.cpp

#include "mainwindow.h"



MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    QToolBar *bar=this->addToolBar("Tools");//将工具栏添加
    QActionGroup *group=new QActionGroup(bar);
    QAction *drawLineAction=new QAction("Line",bar);
    drawLineAction->setToolTip(tr("Draw a line"));
    drawLineAction->setStatusTip(tr("Draw a line"));
    drawLineAction->setCheckable(true);
    drawLineAction->setChecked(true);
    group->addAction(drawLineAction);
    bar->addAction(drawLineAction);
    QAction *drawRectAction=new QAction("Rectangle",bar);
    drawRectAction->setToolTip(tr("Draw a rectangle"));
    drawRectAction->setStatusTip(tr("Draw a rectagle"));
    drawRectAction->setCheckable(true);
    group->addAction(drawRectAction);
    bar->addAction(drawRectAction);

    QLabel *statusMsg=new QLabel;
    statusBar()->addWidget(statusMsg);
    PaintWidget *paintWidget= new PaintWidget(this);
    setCentralWidget(paintWidget);
    connect(drawLineAction,SIGNAL(triggered()),this,SLOT(drawLineActionTriggered()));
    connect(drawRectAction,SIGNAL(triggered()),this,SLOT(drawRectActionTriggered()));
    connect(this,SIGNAL(changeCurrentShape(Shape::Code)),paintWidget,SLOT(setCurrentShape(Shape::Code)));


}
void MainWindow::drawLineActionTriggered()
{
    emit changeCurrentShape(Shape::Line);
}
void MainWindow::drawRectActionTriggered()
{
    emit changeCurrentShape(Shape::Rect);
}

main.cpp

#include "mainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

image.png

从图中可见,GraphicsView提供居中显示。
main.cpp

#include "mainwindow.h"

#include <QApplication>
#include <QtGui>
#include<QGraphicsScene>
#include<QGraphicsView>
class DrawApp : public QWidget{
    public:
        DrawApp();
    protected:
        void paintEvent(QPaintEvent *event);
};
DrawApp::DrawApp()
{

}
void DrawApp::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.drawLine(10,10,150,300);
}
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QGraphicsScene *scene =new QGraphicsScene;
    scene->addLine(10,10,150,300);
    QGraphicsView *view=new QGraphicsView(scene);
    view->resize(500,500);
    view->setWindowTitle("Graphics View");
    view->show();

    DrawApp *da=new DrawApp;
    da->resize(500,500);
    da->setWindowTitle("QWidget");
    da->show();
    return a.exec();
}

QPainterDevice

QPixmap:显示图像,其中QBitmap是它一个黑白图的子类(用isQBitmap()判断)。可以使用QPainter在上面绘图。可以接受图片路径显示,并用drawPixmap()函数把文件绘制到组件上。除此之外还有grabWidget、grabWindow()函数等,将图像绘制到目标上。QPixmap不必使用指针、无法提供像素级操作,显示一致
QImage:像素级的图像访问
QPicture:记录和重现QPainter的命令。使用方法

//记录
QPicture picture; 
QPainter painter; 
painter.begin(&picture);              // paint in picture 
painter.drawEllipse(10,20, 80,70); // draw an ellipse 
painter.end();                           // painting done 
picture.save("drawing.pic");         // save picture

//重现
QPicture picture; 
picture.load("drawing.pic");          // load picture 
QPainter painter; 
painter.begin(&myImage);            // paint in myImage 
painter.drawPicture(0, 0, picture); // draw the picture at (0,0) 
painter.end(); 
旋转

视口与窗口是一致的
世界坐标系通过改变坐标系进行放缩。

QPainter渐变
image.png

重点是:渐变对象要传到QBrush里。如果想画渐变线段,可以把QBrush作为参数传进QPen里。
渐变线段

void PaintedWidget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing,true);
    QLinearGradient linearGradient(60,50,200,200);
    linearGradient.setColorAt(0.2,Qt::white);
    linearGradient.setColorAt(0.6,Qt::green);
    linearGradient.setColorAt(1.0,Qt::black);
    painter.setPen(QPen(QBrush(linearGradient),5));
    painter.drawLine(50,50,200,200);
}

渐变图形


void PaintedWidget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing,true);
    QLinearGradient linearGradient(60,50,200,200);
    linearGradient.setColorAt(0.2,Qt::white);
    linearGradient.setColorAt(0.6,Qt::green);
    linearGradient.setColorAt(1.0,Qt::black);
    painter.setBrush(QBrush(linearGradient));
    //渐变对象传进QBrush里
    painter.drawEllipse(50,50,200,150);
}
QPainter

QPainter:执行绘制操作
QPaintEngine:绘制操作与抽象二维空间的接口
QPaintDevice:二维空间的抽象
this指针是成员函数的隐含参数,在成员函数内部指向调用对象。当我们调用成员函数时,实际上是替某个对象调用它。成员函数通过一个名为 this 的额外隐式参数来访问调用它的那个对象,当我们调用一个成员函数时,用请求该函数的对象地址初始化 this。例如,如果调用 total.isbn()则编译器负责把 total 的地址传递给 isbn 的隐式形参 this。
pen是线框,brush是填充图形
setRenderHint反走样(打开一次后所有的代码都是反走样的)



main.cpp

#include "mainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    PaintedWidget w;
    w.show();
    return a.exec();
}

mainwindow.cpp

#include "mainwindow.h"
#include <QPainter>
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
}

MainWindow::~MainWindow()
{
}

PaintedWidget::PaintedWidget()
{
    resize(800,600);
    setWindowTitle(tr("Paint Demo"));
}

void PaintedWidget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.drawLine(80,100,650,400);
    painter.setPen(Qt::red);
    painter.drawRect(10,10,100,400);
    painter.setPen(QPen(Qt::green,5));
    painter.setBrush(Qt::blue);
    painter.drawEllipse(50,150,400,200);
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>


class PaintedWidget:public QWidget
{
    public:
        PaintedWidget();
    protected:
        void paintEvent(QPaintEvent *event);
};

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
};
#endif // MAINWINDOW_H

自定义事件

事件与信号槽相比,可以是同步的、又可以是异步,而函数调用(槽的回调)总是同步的。同时时间可以使用过滤器。
事件type要大于999(之前的都是保留),介于1000~65535间。

//自定义事件的注册
static int QEvent::registerEventType ( int hint = -1 );

Qt 自定义事件_w3cschool

filter

watched:被监测的对象。函数调用->事件过滤->组件处理。重写时,如果需要过滤某事件需返回true。delete了某个接收组件,需将返回值设为true。
eventFilter()函数建立事件过滤器,installEventFilter()函数安装过滤器。
事件过滤器和被安装的组件需要在同一线程。
QT事件处理分层五个层次:重定义事件处理函数,重定义event()函数,为单个组件安装事件过滤器,为QApplication安装事件过滤器,重定义QCoreApplication的notify()函数。控制权逐层增大

event demo
image.png

accept:事件处理函数接收了该事件,不需要再传递。
ignore:事件处理函数忽略了该事件,需要再传递。
isAccepted:查询事件是不是已经被接收了
不常用,而用响应函数代替。因为子类直接忽略事件,则Qt不会再去寻找其他的接收者,那么父类操作也就不能进行。
窗口关闭时要用。

#include "mainwindow.h"

#include <QApplication>
#include<QWidget>
#include<QLabel>
#include<QMouseEvent>

class EventLabel :public QLabel
{
    protected:
        void mouseMoveEvent(QMouseEvent *event);
        void mousePressEvent(QMouseEvent *event);
        void mouseReleaseEvent(QMouseEvent *event);
};
void EventLabel::mouseMoveEvent(QMouseEvent *event)
{
    this->setText(QString("<center><h1>Move:(%1,%2)</h1></center>").arg(QString::number(event->x()),QString::number(event->y())));
}
void EventLabel::mousePressEvent(QMouseEvent *event)
{
    this->setText(QString("<center><h1>Press:(%1,%2)</h1></center>").arg(QString::number(event->x()),QString::number(event->y())));
}
void EventLabel::mouseReleaseEvent(QMouseEvent *event)
{
    QString msg;
    msg.sprintf("<center><h1>Release:(%d,%d)</h1></center>",event->x(),event->y());
    this->setText(msg);
}

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    EventLabel *label=new EventLabel;
    label->setWindowTitle("MouseEvent Demo");
    label->resize(300,200);
    label->show();
    MainWindow w;
    return app.exec();
}

signal与event区别

signal有具体对象发出,然后立即交给connect函数连接的slot进行处理。事件则是追加到事件队列尾部逐个维护(也可以插队、筛选)。
组件关注信号槽,自定义组件关注事件。
protected virtual :protected可以使被修饰的方法或字段只能在当前类及其子类中使用,防止外部的无意更改。virtual是虚方法,可以由设计人员自行决定是否包含方法的实现。
private:不能被外部访问也不能被继承。也会被编译出现在内存中,但编译器限制程序不能访问private成员
public:可以被外部访问也可以被继承。在编译时直接编译
protected:不能被外部访问但可以被继承
子类可以对父类的函数重写,或在其基础上增加功能。父类的指针可以指向子类对象,编译时是从父类到子类。
构造和析构顺序相反(构造先父后子,析构先子后父)
virtual:当一个成员函数需要子类重写,则在父类应该将其声明为virtual。即将被重写的函数加virtual是良好的编写习惯。加了virtual就只能调用重写的函数了。
父类有多个构造函数时可以显式调用其中一个(通过指定参数)。
类的大小与成员变量有关,与成员函数无关(被声明virtual时大小会有些微编译器决定的变化)。
基类的析构函数要加virtual(不加的时候,基类指针指向派生类delete时,派生类部分清楚导致内存泄漏,加上时,调用基类的析构函数编译器会从虚函数表找到要执行的正确的函数地址,即子类的析构函数),构造函数不能加。
尽量不要多对一地多重继承,成员名重复时会报错。
类的继承参考:(21条消息)
【C++】类的继承(protected,virtual)_protected virtual_mjiansun的博客-CSDN博客

event()

将事件对象按类型分发的函数,可以重写该函数让事件分发前做一些操作、或完成对自定义事件的分发。类型判断:event->type(),返回QEvent::Type的类型枚举。
evnet()返回bool类型,其中true为传入事件已识别且处理,QApplication会继续处理事件队列下一事件。若为false则QApplicaion转去寻找下一个该event的处理函数。

QInputDialog

QLineEdit是参数mode,取值范围:QLineEdit::EchoMode,默认是Normal,如果为password则是密码输入。
&isOK:判断用户按下的是OK还是Cancel
第七个参数:flags指定对话框的样式。
返回QString,通过Ok参数判断是不是true。

    bool isOK;
    QString text=QInputDialog::getText(NULL,"TITLE","Label",QLineEdit::Normal,"your comment",&isOK);
    if(isOK)
    {
        QMessageBox::information(NULL,"Information","your comment is:<b>"+text+"</b>",QMessageBox::Yes||QMessageBox::No,QMessageBox::Yes);
    }
QMessageBox

1.QMessageBox一种是static(返回StandardButton,通过返回值判断)一种是构造函数(通过if判断)。
构造函数:

    //msgbox 构造函数方式
    QMessageBox message(QMessageBox::NoIcon,"Show Qt","Do you want to show qt dialog?",QMessageBox::Yes|QMessageBox::No,NULL);
    if(message.exec()==QMessageBox::Yes)
    {
        QMessageBox::aboutQt(NULL,"About Qt");
    }

static:

    //msgbox static方式返回值
    QMessageBox::StandardButton rb=QMessageBox::question(NULL,"Show QT","Do you want to show Qt dialog?",QMessageBox::Yes|QMessageBox::No,QMessageBox::Yes);
    if(rb==QMessageBox::Yes)
    {
        QMessageBox::aboutQt(NULL,"About Qt");
    }

2.Yes和No按钮:QMessageBox::Yes | QMessageBox::No。msgbox static分类:critical(红色禁止),warning(黄色警告),question(问好),about(没有选择按钮只有Ok)。
3.msg对话框文本支持:支持HTML标签。
4.定义图片:非静态,用exec()而不是show()
5.png格式,相对路径。

QMessageBox message(QMessageBox::NoIcon, "Title", "Content with icon."); 
message.setIconPixmap(QPixmap("icon.png")); 
message.exec();
parent参数

作用:用于指示是否是顶层容器(有parent的就不是顶层容器)。指明组件的父组件,这样在父组件delete时所有的子也会被回收。

QColorDialog

1%%2是占位符,arg()替换掉占位符,QSttring::number()把值替换成等值字符串。这里是把RGB值列出来并输出。

void MainWindow::open()
{
    QString path=QFileDialog::getOpenFileName(this,tr("Open the file"),".",tr("Image Files(*.jpg*.png)"));
    if(path.length()==0)
    {
        QMessageBox::information(NULL,tr("Path"),tr("You didn;t select any files."));
    }
    else
    {
        QMessageBox::information(NULL,tr("Path"),tr("You selected")+path);
    }
//    QMessageBox::information(NULL,tr("Open"),tr("Open a file"));
    QColor color=QColorDialog::getColor(Qt::white,this);
    QString msg=QString("r:%1,g:%2,b").arg(QString::number(color.red()),QString::number(color.green()),QString::number(color.blue()));
    QMessageBox::information(NULL,"Selected color",msg);
}
QFileDialog与getOpenFileName

getOpenFileName函数签名:parent父组件、caption对话框标题、dir默认打开的目录、filter对话框的后缀名过滤器,如需要多个可使用;;分割、selectedFilter默认选择的过滤器、options对话框参数设定,取值为enumQFileDialog::Option,可用|运算组合。
getOpenFileNames()选择多个文件,返回QStringList
另一种写法。getOpenFileNmae是本地对话框,QFileDialog是Qt自己绘制的

QFileDialog *fileDialog = new QFileDialog(this); 
        fileDialog->setWindowTitle(tr("Open Image")); 
        fileDialog->setDirectory("."); 
        fileDialog->setFilter(tr("Image Files(*.jpg *.png)")); 
        if(fileDialog->exec() == QDialog::Accepted) { 
                QString path = fileDialog->selectedFiles()[0]; 
                QMessageBox::information(NULL, tr("Path"), tr("You selected ") + path); 
        } else { 
                QMessageBox::information(NULL, tr("Path"), tr("You didn't select any files.")); 
        }

mainwindow.cpp,添加了文件打开框的实际操作

#include "mainwindow.h"
#include<QAction>
#include<QMenu>
#include<QMenuBar>
#include<QKeySequence>
#include<QToolBar>
#include<QMessageBox>
#include<QLabel>
#include<QStatusBar>
#include<QFileDialog>
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    //定义QAction 创造一个对象
    openAction=new QAction(tr("&Open"),this);
    openAction->setShortcut(QKeySequence::Open);//用于实现跨平台快捷键
    openAction->setStatusTip(tr("Open a file."));//状态栏的提示
    openAction->setIcon(QIcon(":/Open.png"));
    //把QAction添加到菜单和工具条
    connect(openAction,SIGNAL(triggered()),this,SLOT(open()));

    QMenu *file=menuBar()->addMenu(tr("&File"));
    file->addAction(openAction);

    QToolBar *toolBar=addToolBar(tr("&File"));
    toolBar->addAction(openAction);

    msgLabel=new QLabel;
    msgLabel->setMinimumSize(msgLabel->sizeHint());//设置大小为本身建议的大小
    msgLabel->setAlignment(Qt::AlignHCenter);//设置显示规则水平居中
    statusBar()->addWidget(msgLabel);//把label添加到状态栏
    statusBar()->setStyleSheet(QString("QStatusBar::item{border:0px}"));
}

void MainWindow::open()
{
    QString path=QFileDialog::getOpenFileName(this,tr("Open the file"),".",tr("Image Files(*.jpg*.png)"));
    if(path.length()==0)
    {
        QMessageBox::information(NULL,tr("Path"),tr("You didn;t select any files."));
    }
    else
    {
        QMessageBox::information(NULL,tr("Path"),tr("You selected")+path);
    }
//    QMessageBox::information(NULL,tr("Open"),tr("Open a file"));

}
MainWindow::~MainWindow()
{
    }



状态栏

信息类型:临时信息(提示),一般信息(页码),永久信息(不会消失的信息,如按键状态)
demo3
mainwindow.cpp

#include "mainwindow.h"
#include<QAction>
#include<QMenu>
#include<QMenuBar>
#include<QKeySequence>
#include<QToolBar>
#include<QMessageBox>
#include<QLabel>
#include<QStatusBar>
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    //定义QAction 创造一个对象
    openAction=new QAction(tr("&Open"),this);
    openAction->setShortcut(QKeySequence::Open);//用于实现跨平台快捷键
    openAction->setStatusTip(tr("Open a file."));//状态栏的提示
    openAction->setIcon(QIcon(":/Open.png"));
    //把QAction添加到菜单和工具条
    connect(openAction,SIGNAL(triggered()),this,SLOT(open()));

    QMenu *file=menuBar()->addMenu(tr("&File"));
    file->addAction(openAction);

    QToolBar *toolBar=addToolBar(tr("&File"));
    toolBar->addAction(openAction);

    msgLabel=new QLabel;
    msgLabel->setMinimumSize(msgLabel->sizeHint());//设置大小为本身建议的大小
    msgLabel->setAlignment(Qt::AlignHCenter);//设置显示规则水平居中
    statusBar()->addWidget(msgLabel);//把label添加到状态栏
    statusBar()->setStyleSheet(QString("QStatusBar::item{border:0px}"));
}

void MainWindow::open()
{
    QMessageBox::information(NULL,tr("Open"),tr("Open a file"));

}
MainWindow::~MainWindow()
{
    }

main.cpp

#include "mainwindow.h"
#include <QApplication>


int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

class QAction;//前向声明
class QLabel;
class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
private slots:
    void open();
private:
        QAction *openAction;
        QLabel *msgLabel;
};
#endif // MAINWINDOW_H

QAction、工具栏和菜单的demo 添加图标等demo2:

https://www.w3cschool.cn/learnroadqt/7yl81j4f.html

图片.png

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

class QAction;//前向声明

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
private slots:
    void open();
private:
        QAction *openAction;
};
#endif // MAINWINDOW_H

main.cpp

#include "mainwindow.h"
#include <QApplication>


int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

mainwindow.cpp

#include "mainwindow.h"
#include<QAction>
#include<QMenu>
#include<QMenuBar>
#include<QKeySequence>
#include<QToolBar>
#include<QMessageBox>
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    //定义QAction 创造一个对象
    openAction=new QAction(tr("&Open"),this);
    openAction->setShortcut(QKeySequence::Open);//用于实现跨平台快捷键
    openAction->setStatusTip(tr("Open a file."));//状态栏的提示
    openAction->setIcon(QIcon(":/Open.png"));
    //把QAction添加到菜单和工具条
    connect(openAction,SIGNAL(triggered()),this,SLOT(open()));

    QMenu *file=menuBar()->addMenu(tr("&File"));
    file->addAction(openAction);

    QToolBar *toolBar=addToolBar(tr("&File"));
    toolBar->addAction(openAction);
}

void MainWindow::open()
{
    QMessageBox::information(NULL,tr("Open"),tr("Open a file"));

}
MainWindow::~MainWindow()
{
    }



QAction、工具栏和菜单的demo

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

class QAction;//前向声明

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
private:
        QAction *openAction;
};
#endif // MAINWINDOW_H

main.cpp

#include "mainwindow.h"
#include <QApplication>


int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

mainwindow.cpp

#include "mainwindow.h"
#include<QAction>
#include<QMenu>
#include<QMenuBar>
#include<QKeySequence>
#include<QToolBar>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    //定义QAction 创造一个对象
    openAction=new QAction(tr("&Open"),this);
    openAction->setShortcut(QKeySequence::Open);//用于实现跨平台快捷键
    openAction->setStatusTip(tr("Open a file."));//状态栏的提示

    //把QAction添加到菜单和工具条
    QMenu 。菜单是上面的,工具栏是下面的
*file=menuBar()->addMenu(tr("&File"));
    file->addAction(openAction);

    QToolBar *toolBar=addToolBar(tr("&File"));
    toolBar->addAction(openAction);
}

MainWindow::~MainWindow()
{
}


Action类

保存action的信息,如文本描述、图标、快捷键、信号槽

Meta-Object 系统

内省(反射):程序在运行时获取类的相关信息,如方法属性信号列表槽列表,这些基本信息就是meta-information。

信号槽进阶

函数签名:定义函数的输入输出。包含参数及其类型,返回值及其类型,可能抛出传回的异常,可用性信息(public\static\prototype)
一个槽可以连接多个信号(任一信号触发,执行slot),一个信号可以连接多个槽(槽会接连调用,但调用顺序不定,类似verilog),一个信号可以连接一个信号,槽可以被取消链接(disconnect)。
信号和槽的参数个数类型顺序必须一致,多的就会被忽略掉。
通过if防止循环连接
一个典型的类及其使用:

class Employee:public QObject
{
    Q_OBJECT
public:
    Employee() {mySalary=0;}
    int salary() const{return mySalary;}
//const在Public函数中常用,表明该函数不能修改类中的成员变量
public slots:
    void setSalary(int newSalary);
signals:
    void salaryChanged(int newSalary);
private:
    int mySalary;
};

void Employee::setSalary(int newSalary) 
{ 
        if (newSalary != mySalary) { 
                mySalary = newSalary; 
                emit salaryChanged(mySalary); 
        } 
}
week1:

配了环境,qtcreator下cmake的配置仍未解决,无法使用VS,但是原生编辑器能跑。学了layout\信号槽\几个常用组件,用fiddler修改下载源。
ifndef:https://blog.csdn.net/SummerXRT/article/details/119741741
头文件:C 头文件 | 菜鸟教程 (runoob.com)
构造和析构:C++构造函数和析构函数详解 - 知乎 (zhihu.com)

image.png

示例:
main.cpp

#include<QApplication>
#include"finddialog.h"

int main(int argc,char *argv[])
{
    QApplication app(argc,argv);
    FindDialog *dialog = new FindDialog;
    dialog->show();
    return app.exec();
}

FindDialog.cpp
::和:https://blog.csdn.net/qingkongyeyue/article/details/52948266

#include <QtGui>
#include "finddialog.h"

FindDialog::FindDialog(QWidget *parent)
    :QDialog(parent)
{
    label = new QLabel(tr("Find &what:"));
    lineEdit = new QLineEdit;
    label->setBuddy(lineEdit);

    caseCheckBox = new QCheckBox(tr("Match &case"));
    backwardCheckBox = new QCheckBox(tr("Search &backford"));

    findButton = new QPushButton(tr("&Find"));
    findButton->setDefault(true);
    findButton->setEnabled(false);

    closeButton = new QPushButton(tr("Close"));

    connect(lineEdit,SIGNAL(textChanged(const QString&)),this,SLOT(enableFindButton(const QString&)));
    connect(findButton,SIGNAL(clicked()),this,SLOT(findClicked()));
    connect(closeButton,SIGNAL(clicked()),this,SLOT(close()));

    QHBoxLayout *topLeftLayout = new QHBoxLayout;
    topLeftLayout->addWidget(label);
    topLeftLayout->addWidget(lineEdit);

    QVBoxLayout *leftLayout=new QVBoxLayout;
    leftLayout->addLayout(topLeftLayout);
    leftLayout->addWidget(caseCheckBox);
    leftLayout->addWidget(backwardCheckBox);

    QVBoxLayout *rightLayout=new QVBoxLayout;
    rightLayout->addWidget(findButton);
    rightLayout->addWidget(closeButton);
    rightLayout->addStretch();

    QHBoxLayout *mainLayout=new QHBoxLayout;
    mainLayout->addLayout(leftLayout);
    mainLayout->addLayout(rightLayout);
    setLayout(mainLayout);

    setWindowTitle(tr("Find"));
    setFixedHeight(sizeHint().height());
}
FindDialog::~FindDialog()
{

}
void FindDialog::findClicked()
{
    QString text = lineEdit->text();
    Qt::CaseSensitivity cs=caseCheckBox->isChecked()?Qt::CaseInsensitive : Qt::CaseSensitive;
    if(backwardCheckBox->isChecked())
    {
        emit findPrevious(text,cs);
    }else
    {
        emit findNext(text,cs);
    }
}
void FindDialog::enableFindButton(const QString &text)
{
    findButton->setEnabled(!text.isEmpty());
}

.h文件:

#ifndef FINDDIALOG_H
#define FINDDIALOG_H

#include<QDialog>
#include<QLabel>
#include<QLineEdit>
#include<QCheckBox>
#include<QApplication>
#include<QHBoxLayout>
#include<QVBoxLayout>
#include<QPushButton>

class QCheckBox;
class QLabel;
class QLineEdit;
class QPushButton;


class FindDialog : public QDialog
{
    Q_OBJECT

public:
    FindDialog(QWidget *parent = 0);
    ~FindDialog();
signals:
    void findNext(const QString &str,Qt::CaseSensitivity cs);
    void findPrevious(const QString &str,Qt::CaseSensitivity cs);
private slots:
    void findClicked();
    void enableFindButton(const QString &text);
private:
    QLabel *label;
    QLineEdit *lineEdit;
    QCheckBox *caseCheckBox;
    QCheckBox *backwardCheckBox;
    QPushButton *findButton;
    QPushButton *closeButton;
};
#endif // FINDDIALOG_H

参考资料

qt镜像站:https://mirrors.tuna.tsinghua.edu.cn/qt/archive/qt/
组件更新:
https://blog.csdn.net/SHIE_Ww/article/details/124074573
教程:https://www.w3cschool.cn/learnroadqt/c84q1j3t.html
qt串口通信:https://shenmingyi.blog.csdn.net/article/details/81669540?spm=1001.2101.3001.6650.5&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-5-81669540-blog-123432413.235%5Ev28%5Epc_relevant_t0_download&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-5-81669540-blog-123432413.235%5Ev28%5Epc_relevant_t0_download

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容