先说一下结论,QT界面编程一般是可视化UI设计和Code编码来设计实现,可视化能设计的code都可以,但反之却不行。
Hello World开局
0、信号槽
1、QT 学习之路 2(5):自定义信号槽
不得不说,大神真牛,有几处我特别摘抄,因为写的太透彻了
下面总结一下自定义信号槽需要注意的事项:
发送者和接收者都需要是QObject的子类(当然,槽函数是全局函数、Lambda 表达式等无需接收者的时候除外);
使用 signals 标记信号函数,信号是一个函数声明,返回 void,不需要实现函数代码;
槽函数是普通的成员函数,作为成员函数,会受到 public、private、protected 的影响;
使用 emit 在恰当的位置发送信号;
使用QObject::connect()函数连接信号和槽。
2、QT模块简介
3、mainWindow简介
4、添加动作
5、资源文件
6、对象模型
7、布局管理器
里面有几行代码很nice
QObject::connect(slider, &QSlider::valueChanged, spinBox, &QSpinBox::setValue);
void (QSpinBox:: *spinBoxSignal)(int) = &QSpinBox::valueChanged;
QObject::connect(spinBox, spinBoxSignal, slider, &QSlider::setValue);
8、对话框简介
里面提到了一个变量在堆上建立和变量在栈上建立的区别。此处也有讲解,还算比较透彻。
C++:在堆上创建对象,还是在栈上?
9、对话框数据传递,这也是重点部分
QDialog dialog(this);
if (dialog.exec() == QDialog::Accepted) {
// do something
} else {
// do something else
}
10、标准对话框QMessageBox
常用的方法如下:
QMessageBox msgBox;
msgBox.setText(tr("The document has been modified."));
msgBox.setInformativeText(tr("Do you want to save your changes?"));
msgBox.setDetailedText(tr("Differences here..."));
msgBox.setStandardButtons(QMessageBox::Save
| QMessageBox::Discard
| QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Save);
int ret = msgBox.exec();
switch (ret) {
case QMessageBox::Save:
qDebug() << "Save document!";
break;
case QMessageBox::Discard:
qDebug() << "Discard changes!";
break;
case QMessageBox::Cancel:
qDebug() << "Close document!";
break;
}
11、QT5信号槽新语法
12、C++lambda表达式语法规范
lambda表达式详细介绍
13、文件对话框
14、事件
Qt 中的事件和信号槽却并不是可以相互替代的。信号由具体的对象发出,然后会马上交给由connect()函数连接的槽进行处理;而对于事件,Qt 使用一个事件队列对所有发出的事件进行维护,当新的事件产生时,会被追加到事件队列的尾部。前一个事件完成后,取出后面的事件进行处理。但是,必要的时候,Qt 的事件也可以不进入事件队列,而是直接处理。信号一旦发出,对应的槽函数一定会被执行。但是,事件则可以使用“事件过滤器”进行过滤,对于有些事件进行额外的处理,另外的事件则不关心。总的来说,如果我们使用组件,我们关心的是信号槽;如果我们自定义组件,我们关心的是事件。因为我们可以通过事件来改变组件的默认操作。
事件是不需要connect函数的。
15、事件的接受与忽略
这个地方其实也描述了事件与信号槽的关系:信号是由事件发出的,文章中也说了:一般来说,使用 Qt 组件时,我们并不会把主要精力放在事件上。因为在 Qt 中,我们关心的更多的是事件关联的一个信号。当然在发送信号之前,事件可以做自己的操作,甚至可以决定是否发送信号。
16、Event()
event()函数主要用于事件的分发。所以,如果你希望在事件分发之前做一些操作,就可以重写这个event()函数了。
bool CustomWidget::event(QEvent *e)
{
if (e->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(e);
if (keyEvent->key() == Qt::Key_Tab) {
qDebug() << "You press tab.";
return true;
}
}
return QWidget::event(e);
}
在event()函数中,调用事件对象的accept()和ignore()函数是没有作用的,不会影响到事件的传播
bool CustomTextEdit::event(QEvent *e)
{
if (e->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(e);
if (keyEvent->key() == Qt::Key_Tab) {
qDebug() << "You press tab.";
return true;
}
}
return false;
}
Qt 也是使用QEvent::type()判断事件类型,然后调用了特定的事件处理器。
//!!! Qt5
bool QObject::event(QEvent *e)
{
switch (e->type()) {
case QEvent::Timer:
timerEvent((QTimerEvent*)e);
break;
case QEvent::ChildAdded:
case QEvent::ChildPolished:
case QEvent::ChildRemoved:
childEvent((QChildEvent*)e);
break;
// ...
default:
if (e->type() >= QEvent::User) {
customEvent(e);
break;
}
return false;
}
return true;
}
event()函数中实际是通过事件处理器来响应一个具体的事件。这相当于event()函数将具体事件的处理“委托”给具体的事件处理器。而这些事件处理器是 protected virtual 的,因此,我们重写了某一个事件处理器,即可让 Qt 调用我们自己实现的版本。
事实也的确如此。timerEvent()和mouseMoveEvent()这样的函数,就是我们前面章节所说的事件处理器 event handler。
就是说,event()函数中实际是通过事件处理器来响应一个具体的事件。这相当于event()函数将具体事件的处理“委托”给具体的事件处理器。而这些事件处理器是 protected virtual 的,因此,我们重写了某一个事件处理器,即可让 Qt 调用我们自己实现的版本。
17、事件过滤器
class MainWindow : public QMainWindow
{
public:
MainWindow();
protected:
bool eventFilter(QObject *obj, QEvent *event);//重载过滤器
private:
QTextEdit *textEdit;
};
MainWindow::MainWindow()
{
textEdit = new QTextEdit;
setCentralWidget(textEdit);
textEdit->installEventFilter(this);//重点,安装过滤器
}
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if (obj == textEdit) {
if (event->type() == QEvent::KeyPress) {
//只过滤符合条件的
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
qDebug() << "Ate key press" << keyEvent->key();
return true;
} else {
return false;
}
} else {
// pass the event on to the parent class
return QMainWindow::eventFilter(obj, event);
}
}
事件过滤器会检查接收到的事件。如果这个事件是我们感兴趣的类型,就进行我们自己的处理;如果不是,就继续转发。这个函数返回一个 bool 类型,如果你想将参数 event 过滤出来,比如,不想让它继续转发,就返回 true,否则返回 false。
18、事件总结
下面这段代码很重要
class Label : public QWidget
{
public:
Label()
{
installEventFilter(this);
}
bool eventFilter(QObject *watched, QEvent *event)
{
if (watched == this) {
if (event->type() == QEvent::MouseButtonPress) {
qDebug() << "eventFilter";
}
}
return false;
}
protected:
void mousePressEvent(QMouseEvent *)
{
qDebug() << "mousePressEvent";
}
bool event(QEvent *e)
{
if (e->type() == QEvent::MouseButtonPress) {
qDebug() << "event";
}
return QWidget::event(e);
}
};
class EventFilter : public QObject
{
public:
EventFilter(QObject *watched, QObject *parent = 0) :
QObject(parent),
m_watched(watched)
{
}
bool eventFilter(QObject *watched, QEvent *event)
{
if (watched == m_watched) {
if (event->type() == QEvent::MouseButtonPress) {
qDebug() << "QApplication::eventFilter";
}
}
return false;
}
private:
QObject *m_watched;
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Label label;
app.installEventFilter(new EventFilter(&label, &label));
label.show();
return app.exec();
}
运行结果为:
QApplication::eventFilter
eventFilter
event
mousePressEvent
全局事件过滤器被第一个调用,返回false后,事件传回给label对象,之后是该对象上面的事件过滤器调用,依旧返回false,其次是event()函数,其实也就是事件分发函数,处理之后调用return QWidget::event(e),把事件扔给父组件,最后是特定的事件处理函数。
19、自定义事件
20、QT绘制系统简介
21、画刷和画笔
22、防走样
23、渐变
24、坐标系统
25、绘制设备
26、使用多态需要注意的问题
所谓动态绑定,也称为“运行时绑定”,是指在执行期间(非编译期)判断所引用对象的实际类型。
多态(动态绑定)的实现,也就是虚函数的调用,是建立在虚表的基础之上。
在 C++ 中,不应该在构造函数中调用被子类重写的虚函数,因为虚表还没有构造完成。
另外,在这篇文章中描述了一种叫做静态多态的技术:
template<class Derived>
class Base
{
public:
Base()
{
static_cast<Derived *>(this)->calc(); // Derived::calc()
}
void calc() { cout << "Base::calc()" << endl; } // 注意,没有 virtual 关键字!
};
class Derived : public Base<Derived>
{
public:
void calc() { cout << "Derived::calc()" << endl; }
};
它的目的是:在父类中调用子类的版本,目前还没有这种需求,先码了,后续再看
27、C++11新特性,写的很不错
C++为什么那么讨人喜欢,因为它虽然是大佬却那么的与时俱进:
这里面提到了几个新技术,列一下:
1、Lambda 表达式
2、自动类型推断auto
3、统一初始化语法
4、删除和默认函数
5、nullptr
const char *pc = str.c_str(); // 数据指针
if (pc != nullptr)
cout << pc << endl;
int (A::*pmf)() = nullptr; // 成员函数指针
void (*pmf)() = nullptr; // 函数指针
6、委托构造函数
class M // C++11 委托构造函数
{
int x, y;
char *p;
public:
M(int v) : x(v), y(0), p(new char [MAX]) {} // #1 目标
M(): M(0) {cout << "delegating ctor" << endl;} // #2 委托
};
7、右值引用
8、许多新的算法
28、QT信号槽的实现
29、QT5中信号槽新语法的实现
30、Graph View框架
31、贪吃蛇游戏1
32、贪吃蛇游戏2
33、贪吃蛇游戏3
34、贪吃蛇游戏4
新篇章
35、文件
36、二进制文件读写
37、文本文件读写
38、存储容器,也就是C++ STL的QT版本
39、遍历容器
40、隐式数据共享
下面将了不少控件
41、model view架构
42、QListWidget-QTreeWidget-QTableWidget,应该就是列表、树和表格控件的使用。
43、QStringListModel
44、QFileSystemModel,文件系统,很厉害的
45、Model,也就是模型
46、视图与委托
47、视图选择
48、QSortFilterProxyModel
49、自定义只读模型
50、使用VS2012编译QT,这个不一定有用,先留着吧
51、自定义可编辑模型
52、布尔表达树模型
53、使用拖放
54、自定义拖放数据
55、剪贴板
56、数据库操作
57、使用模型操作数据库
58、可视化显示数据库数据
59、编辑数据库外键
60、使用流处理XML
61、使用DOM处理XML
62、使用sax处理XML
63、保存XML
64、使用QJson处理Json
65、使用QJsonDocument处理JSON
66、访问网络
67、访问网络2
68、访问网络3
69、访问网络4
70、进程,这个可以划重点
71、进程间通信
72、线程简介
73、线程和事件循环
74、QT线程相关类
75、线程和QObject
76、线程总结
77、QML和QT quick2
78、QML文档
79、QML基本元素
80、QML组件
81、宏相关,这个不看也行
下面估计又是界面布局相关的
82、定位器
83、元素布局
84、输入元素TextInput和TextEdit
下面就是作者的一些想法
选择 Qt Widgets 还是 QtQuickControls
有关 QString::toStdString() 使用的一个细节问题
虚继承及一些技巧
使 WINDOWS 下的 QT 应用程序获得 ADMINISTRATOR 权限
85、QtQuickControls
86、Repeater
87、动态视图
88、视图代理delegate
89、模型视图高级技术
90、canvas
91、canvas续
92、粒子系统
93、粒子系统2
94、QML存储
95、使用C++扩展QML
96、使用C++扩展QML2
最后是作者大大网站的首页,以后要多多感谢,多多学习
后面是自己认为也有必要学的东西:
1、std::function详解
2、函数指针讲解1
3、函数指针讲解2
QT Creator使用的几个小技巧
其中,划横线的部分尤其是重要,特别是F1。
4、QT中使用cout的方法,习惯了基本的C++语法,cout比qDebug怎么着都方便多了吧!