这里写目录标题
- [第0课 - 开发环境搭建](#第0课 - 开发环境搭建)
- [第1课 - GUI 程序原理分析](#第1课 - GUI 程序原理分析)
- [第2课 - GUI 程序实例分析](#第2课 - GUI 程序实例分析)
- [第3课 - QT 的诞生和本质](#第3课 - QT 的诞生和本质)
- [第4课 - Hello QT](#第4课 - Hello QT)
- [第5课 - Qt Creator工程介绍](#第5课 - Qt Creator工程介绍)
- [第6课 - 窗口部件及窗口类型](#第6课 - 窗口部件及窗口类型)
- [第7课 - Qt 中的坐标系统](#第7课 - Qt 中的坐标系统)
- [第8课 - 启航!第一个应用实例](#第8课 - 启航!第一个应用实例)
- [第9课 - 计算器界面代码重构](#第9课 - 计算器界面代码重构)
- [第10课 - 初探 Qt 中的消息处理](#第10课 - 初探 Qt 中的消息处理)
- [第11课 - Qt 中的字符串类](#第11课 - Qt 中的字符串类)
- [第12课 - 计算器核心解析算法(上)](#第12课 - 计算器核心解析算法(上))
- [第13课 - 计算器核心解析算法(中)](#第13课 - 计算器核心解析算法(中))
- [第14课 - 计算器核心解析算法(下)](#第14课 - 计算器核心解析算法(下))
- [第15课 - 用户界面与业务逻辑的分离](#第15课 - 用户界面与业务逻辑的分离)
- [第16课 - Qt 对象间的父子关系](#第16课 - Qt 对象间的父子关系)
- [第17课 - 对话框及其类型](#第17课 - 对话框及其类型)
- [第18课 - 登录对话框实例分析](#第18课 - 登录对话框实例分析)
- [第19课 - Qt 中的标准对话框(上)](#第19课 - Qt 中的标准对话框(上))
- [第20课 - Qt 中的标准对话框(中)](#第20课 - Qt 中的标准对话框(中))
- [第21课 - Qt 中的标准对话框(下)](#第21课 - Qt 中的标准对话框(下))
- [第22课 - 布局管理器(一)](#第22课 - 布局管理器(一))
- [第23课 - 布局管理器(二)](#第23课 - 布局管理器(二))
- [第24课 - 布局管理器(三)](#第24课 - 布局管理器(三))
- [第25课 - 布局管理器(四)](#第25课 - 布局管理器(四))
- [第26课 - 布局管理综合实例](#第26课 - 布局管理综合实例)
- [第27课 - 应用程序中的主窗口](#第27课 - 应用程序中的主窗口)
- [第28课 - 主窗口中的工具栏](#第28课 - 主窗口中的工具栏)
- [第29课 - 主窗口中的状态栏](#第29课 - 主窗口中的状态栏)
- [第30课 - Qt 中的文本编辑组件](#第30课 - Qt 中的文本编辑组件)
- [第31课 - 软件开发流程简介](#第31课 - 软件开发流程简介)
- [第32课 - Qt 中的文件操作](#第32课 - Qt 中的文件操作)
- [第33课 - 文本流和数据流](#第33课 - 文本流和数据流)
- [第34课 - 缓冲区操作与目录操作](#第34课 - 缓冲区操作与目录操作)
- [第35课 - 文本编辑器中的数据存取](#第35课 - 文本编辑器中的数据存取)
- [第36课 - 文本编辑器中的功能交互](#第36课 - 文本编辑器中的功能交互)
- [第37课 - 深度解析 QMap 与 QHash](#第37课 - 深度解析 QMap 与 QHash)
- [第38课 - Qt 中的事件处理(上)](#第38课 - Qt 中的事件处理(上))
- [第39课 - Qt 中的事件处理(下)](#第39课 - Qt 中的事件处理(下))
- [第40课 - 拖放事件深度剖析](#第40课 - 拖放事件深度剖析)
- [第41课 - 编辑交互功能的实现](#第41课 - 编辑交互功能的实现)
- [第42课 - 文本打印与光标定位](#第42课 - 文本打印与光标定位)
- [第43课 - 发送自定义事件(上)](#第43课 - 发送自定义事件(上))
- [第44课 - 发送自定义事件(下)](#第44课 - 发送自定义事件(下))
- [第45课 - 创建查找对话框](#第45课 - 创建查找对话框)
- [第46课 - 查找对话框的功能实现](#第46课 - 查找对话框的功能实现)
- [第47课 - Qt 中的调色板](#第47课 - Qt 中的调色板)
- [第48课 - 替换对话框的设计与实现](#第48课 - 替换对话框的设计与实现)
- [第49课 - 文本编辑器项目持续开发](#第49课 - 文本编辑器项目持续开发)
- [第50课 - 关于对话框(About)](#第50课 - 关于对话框(About))
- [第51课 - 程序中的配置文件](#第51课 - 程序中的配置文件)
- [第52课 - 命令行参数的应用](#第52课 - 命令行参数的应用)
- [第53课 - 应用程序的打包与发布](#第53课 - 应用程序的打包与发布)
- [第54课 - Qt 中的多页面切换组件](#第54课 - Qt 中的多页面切换组件)
- [第55课 - 模型视图设计模式(上)](#第55课 - 模型视图设计模式(上))
- [第56课 - 模型视图设计模式(中)](#第56课 - 模型视图设计模式(中))
- [第57课 - 模型视图设计模式(下)](#第57课 - 模型视图设计模式(下))
- [第58课 - 自定义模型类(上)](#第58课 - 自定义模型类(上))
- [第59课 - 自定义模型类(中)](#第59课 - 自定义模型类(中))
- [第60课 - 自定义模型类(下)](#第60课 - 自定义模型类(下))
- [第61课 - 模型视图中的委托(上)](#第61课 - 模型视图中的委托(上))
- [第62课 - 模型视图中的委托(下)](#第62课 - 模型视图中的委托(下))
- [第63课 - 深入解析视图与委托(上)](#第63课 - 深入解析视图与委托(上))
- [第64课 - 深入解析视图与委托(下)](#第64课 - 深入解析视图与委托(下))
- [第65课 - 深入浅出信号与槽](#第65课 - 深入浅出信号与槽)
- [第66课 - 基础图形绘制(上)](#第66课 - 基础图形绘制(上))
- [第67课 - 基础图形绘制(中)](#第67课 - 基础图形绘制(中))
- [第68课 - 基础图形绘制(下)](#第68课 - 基础图形绘制(下))
- [第69课 - 图像处理与绘制](#第69课 - 图像处理与绘制)
- [第70课 - 文本绘制技巧](#第70课 - 文本绘制技巧)
- [第71课 - 登录对话框的改进](#第71课 - 登录对话框的改进)
- [第72课 - 进程与线程的概念](#第72课 - 进程与线程的概念)
- [第73课 - Qt 中的多线程编程](#第73课 - Qt 中的多线程编程)
- [第74课 - 多线程间的同步](#第74课 - 多线程间的同步)
- [第75课 - 多线程间的互斥(上)](#第75课 - 多线程间的互斥(上))
- [第76课 - 多线程间的互斥(下)](#第76课 - 多线程间的互斥(下))
- [第77课 - 银行家算法的分析与实现](#第77课 - 银行家算法的分析与实现)
- [第78课 - 多线程中的信号与槽(上)](#第78课 - 多线程中的信号与槽(上))
- [第79课 - 多线程中的信号与槽(中)](#第79课 - 多线程中的信号与槽(中))
- [第80课 - 多线程中的信号与槽(下)](#第80课 - 多线程中的信号与槽(下))
- [第81课 - 信号与槽的连接方式](#第81课 - 信号与槽的连接方式)
- [第82课 - 线程的生命期问题](#第82课 - 线程的生命期问题)
- [第83课 - 另一种创建线程的方式](#第83课 - 另一种创建线程的方式)
- [第84课 - 多线程与界面组件的通信(上)](#第84课 - 多线程与界面组件的通信(上))
- [第85课 - 多线程与界面组件的通信(下)](#第85课 - 多线程与界面组件的通信(下))
第0课 - 开发环境搭建
第1课 - GUI 程序原理分析
第2课 - GUI 程序实例分析

增加点击X,退出程序的功能
cpp
static HWND MainWindow = NULL; // 主窗口句柄标 移动位置
void App_Exit()
{
PostQuitMessage(0);
}
void Button_handler(int i,int e)
{
if((i==BUTTON_ID)&& (e==BN_CLICKED))
{
MessageBox(MainWindow,L"My button is clicked",L"Click message",0);
}
}
//static HWND MainWindow = NULL; // 主窗口句柄标 移动到上面
.......
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if(message==WM_DESTROY)
{
//PostQuitMessage(0);
App_Exit();//
}
if(message==WM_COMMAND)
{
Button_handler(LOWORD(wParam),HIWORD(wParam));//获取id值
}
/* 调用系统提供的默认消息处理函数 */
return DefWindowProc(hWnd, message, wParam, lParam);
}
MFC应用程序创建
cpp
void CMFCdemoDlg::OnClickedMyButton1()
{
// TODO: 在此添加控件通知处理程序代码
MessageBox(L"my button is clicked");
}
在字符串前加一个L作用: unicode字符集是两个字节组成的。L告示编译器使用两个字节的 unicode 字符集。
如 L"我的字符串" 表示将ANSI字符串转换成unicode的字符串,就是每个字符占用两个字节。
第3课 - QT 的诞生和本质
上一课的代码使用的是面向过程的方法,所以只有一个文件
这节课是面向对象的方法,多个cpp文件
cpp
#pragma once//??啥意思来着 这个文件只能编译一次
#include <windows.h>
class Application
{
public:
Application(HINSTANCE hInstance, LPSTR lpCmdLine);
bool exec();
};
第4课 - Hello QT

条件断点
第5课 - Qt Creator工程介绍
第6课 - 窗口部件及窗口类型

cpp
#include <QLabel>
//#include <QtGui>//qlabel 版本不一样
#include "Widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// QWidget w;//Widget w;
// QWidget w(NULL,Qt::Dialog);
//QWidget w(NULL,Qt::Window);
// QWidget w(NULL,Qt::SplashScreen);
//QWidget w(NULL,Qt::Window|Qt::WindowStaysOnTopHint);
QWidget w(NULL,Qt::Window|Qt::WindowStaysOnTopHint|Qt::WindowContextHelpButtonHint);
QLabel l(&w);
l.setText("this is a label");
w.setWindowTitle("title");
w.show();/**/
/*label也可以是窗体
QLabel l;
l.setText("this is a label");
l.setWindowTitle("title");
l.show();*/
return a.exec();
}
第7课 - Qt 中的坐标系统
第8课 - 启航!第一个应用实例
cpp
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
cpp
//#include "widget.h"
#include <QApplication>
#include<QWidget>
#include<QLineEdit>
#include<QPushButton>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//Widget w;
QWidget *w=new QWidget(NULL,Qt::WindowCloseButtonHint);//窗口最大化优化 WindowMaximizeButtonHint
QLineEdit *e=new QLineEdit(w);
e->setReadOnly(true);
e->resize(240,30);
e->move(10,10);
QPushButton* button[20]={0};
const char* texts[20]={
"7","8","9","+","(",
"4","5","6","-",")",
"1","2","3","*","<-",
"0",".","=","/","C",
};
for(int i=0;i<4;i++)
{
for(int j=0;j<5;j++)
{
button[i*5+j]=new QPushButton(w);
button[i*5+j]->resize(40,40);
button[i*5+j]->move(10+(10+40)*j,50+(10+40)*i);
button[i*5+j]->setText(texts[i*5+j]);
}
}
int ret=0;
//w.show();
w->show();
w->setFixedSize(w->width(),w->height());//放在show后面
//return a.exec();
ret=a.exec();
delete w;
return ret;
}
第9课 - 计算器界面代码重构
c
#include "calculatorui.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//Widget w;
/*
QWidget *w=new QWidget(NULL,Qt::WindowCloseButtonHint);//窗口最大化优化 WindowMaximizeButtonHint
QLineEdit *e=new QLineEdit(w);
e->setReadOnly(true);
e->resize(240,30);
e->move(10,10);
QPushButton* button[20]={0};
const char* texts[20]={
"7","8","9","+","(",
"4","5","6","-",")",
"1","2","3","*","<-",
"0",".","=","/","C",
};
for(int i=0;i<4;i++)
{
for(int j=0;j<5;j++)
{
button[i*5+j]=new QPushButton(w);
button[i*5+j]->resize(40,40);
button[i*5+j]->move(10+(10+40)*j,50+(10+40)*i);
button[i*5+j]->setText(texts[i*5+j]);
}
}
*/
CalculatorUI * c1=CalculatorUI::newInstance();
int ret=-1;
if(c1!=NULL)
{
c1->show();
ret=a.exec();
delete c1;
}
//w.show();
/*
w->show();
w->setFixedSize(w->width(),w->height());//放在show后面
*/
//return a.exec();
//delete w;
return ret;
}
c
#ifndef _CALCULATORUI_H
#define _CALCULATORUI_H
#include <QApplication>
#include<QWidget>
#include<QLineEdit>
#include<QPushButton>
class CalculatorUI:public QWidget
{
private:
QLineEdit *m_e;
QPushButton* m_button[20];
CalculatorUI();
bool construct();
public:
static CalculatorUI* newInstance();
void show();
~CalculatorUI();
};
#endif // CALCULATORUI_H
c
#include "calculatorui.h"
CalculatorUI::CalculatorUI():QWidget(NULL,Qt::WindowCloseButtonHint)
{
//非系统变量
}
bool CalculatorUI::construct()
{
bool ret=true;
const char* texts[20]={
"7","8","9","+","(",
"4","5","6","-",")",
"1","2","3","*","<-",
"0",".","=","/","C",
};
m_e=new QLineEdit(this);
if(m_e!=NULL)
{
m_e->setReadOnly(true);
m_e->resize(240,30);
m_e->move(10,10);
//ret=true;
}
else
{
ret=false;
}
for(int i=0;(i<4)&&ret;i++)//&&ret
{
for(int j=0;(j<5)&&ret;j++)
{
m_button[i*5+j]=new QPushButton(this);
if(m_button[i*5+j]!=NULL)
{
m_button[i*5+j]->resize(40,40);
m_button[i*5+j]->move(10+(10+40)*j,50+(10+40)*i);
m_button[i*5+j]->setText(texts[i*5+j]);
// ret=true;
}
else
{
ret=false;
}
}
}
return ret;
}
CalculatorUI* CalculatorUI::newInstance()
{
CalculatorUI* ret=new CalculatorUI();
if((ret==NULL)||ret->construct()==false)//CalculatorUI::construct()==false
{
delete ret;
ret=NULL;
}
return ret;
}
void CalculatorUI::show()//CalculatorUI* obj
{
QWidget::show();//obj-> QWidget:: CalculatorUI::XXX 死循环??
setFixedSize(width(),height());
}
CalculatorUI::~CalculatorUI()
{
delete(m_e);
for(int i=0;i<20;i++)
{
delete(m_button[i]);
}
}
第10课 - 初探 Qt 中的消息处理
第11课 - Qt 中的字符串类

c
#include <QDebug>
void Sample_1()
{
QString s = "add";
s.append(" "); // "add "
s.append("Qt"); // "add Qt"
s.prepend(" "); // " add Qt"
s.prepend("C++"); // "C++ add Qt"
qDebug() << s;
s.replace("add", "&"); // "C++ & Qt"
qDebug() << s;
}
void Sample_2()
{
QString s = "";
int index = 0;
s.sprintf("%d. I'm %s, thank you!", 1, "Delphi Tang"); // "1. I'm Delphi Tang, thank you!"
qDebug() << s;
index = s.indexOf(",");
s = s.mid(0, index); // "1. I'm Delphi Tang"
qDebug() << s;
index = s.indexOf(".");
s = s.mid(index + 1, s.length()); // " I'm Delphi Tang"
s = s.trimmed(); // "I'm Delphi Tang"
qDebug() << s;
index = s.indexOf(" ");
s = s.mid(index + 1, s.length()); // "Delphi Tang"
qDebug() << s;
}
void Sample_3(QString* a, int len)
{
for(int i=0; i<len; i++)
{
for(int j=i+1; j<len; j++)
{
if( a[j] < a[i] )
{
QString tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
}
}
}
int main()
{
qDebug() << "Sample_1:";
Sample_1();
qDebug() << endl;
qDebug() << "Sample_2:";
Sample_2();
qDebug() << endl;
qDebug() << "Sample_3:";
QString company[5] =
{
QString("Oracle"),
QString("Borland"),
QString("Microsoft"),
QString("IBM"),
QString("D.T.Software")
};
Sample_3(company, 5);
for(int i=0; i<5; i++)
{
qDebug() << company[i];
}
return 0;
}

第12课 - 计算器核心解析算法(上)
第13课 - 计算器核心解析算法(中)
遇到问题
"+9.11"
"+"
"-"
"3"
"-"
"1"
"*"
"-"
"5" 应该是-5
c
QQueue<QString> CalculatorDec::split(const QString& exp)// 日期:8/28
{
QQueue<QString> ret;
QString num="";
QString pre="";
for(int i=0;i<exp.length();i++)
{
if(isDigitorDot(exp[i]))//数字和点
{
num+=exp[i]; //QString Qchar
pre=exp[i];
}
else if(isSymbol(exp[i]))//加减乘除括号 isOperator QString转换为Qchar类型XXX 本来就是Qchar
{
if(!num.isEmpty())//有内容,数值丢到队列去 num!=""!num.isEmpty()
{
ret.enqueue(num);
num.clear();//="";
}
if(isSign(exp[i]) &&((pre=="")||isOperator(pre)||("("==pre)))//当前是否是正负号(首位,前面是加减乘除,前面是括号) isSign(exp[i]) && duole ||isRight(pre)
{
num+=exp[i];//
}
else
{
ret.enqueue(exp[i]);
}
pre=exp[i];
}
//pre=exp[i];不能放这里
}
if( !num.isEmpty() )//防止最后一位数值漏了
{
ret.enqueue(num);
}
/*
for(int i=0; i<exp.length(); i++)
{
if( isDigitorDot(exp[i]) )
{
num += exp[i];
pre = exp[i];
}
else if( isSymbol(exp[i]) )
{
if( !num.isEmpty() )
{
ret.enqueue(num);
num.clear();
}
if( isSign(exp[i]) && ((pre == "") || (pre == "(") || isOperator(pre)) )
{
num += exp[i];
}
else
{
ret.enqueue(exp[i]);
}
pre = exp[i];
}
}
if( !num.isEmpty() )
{
ret.enqueue(num);
}
*/
return ret;
}
bool QCalculatorDec::transform(QQueue& exp, QQueue& output)
{
bool ret = match(exp);
QStack stack;
output.clear();
while( ret && !exp.isEmpty() )
{
QString e = exp.dequeue();
if( isNumber(e) )
{
output.enqueue(e);
}
else if( isOperator(e) )
{
while( !stack.isEmpty() && (priority(e) <= priority(stack.top())) )
{
output.enqueue(stack.pop());
}
stack.push(e);
}
else if( isLeft(e) )
{
stack.push(e);
}
else if( isRight(e) )
{
while( !stack.isEmpty() && !isLeft(stack.top()) )
{
output.enqueue(stack.pop());
}
if( !stack.isEmpty() )
{
stack.pop();
}
}
else
{
ret = false;
}
}
while( !stack.isEmpty() )
{
output.enqueue(stack.pop());
}
if( !ret )
{
output.clear();
第14课 - 计算器核心解析算法(下)
c
QString QCalculatorDec::calculate(QString l, QString op, QString r)
{
QString ret = "Error";
if( isNumber(l) && isNumber(r) )
{
double lp = l.toDouble();
double rp = r.toDouble();
if( op == "+" )
{
ret.sprintf("%f", lp + rp);
}
else if( op == "-" )
{
ret.sprintf("%f", lp - rp);
}
else if( op == "*" )
{
ret.sprintf("%f", lp * rp);
}
else if( op == "/" )
{
const double P = 0.000000000000001;
if( (-P < rp) && (rp < P) )
{
ret = "Error";
}
else
{
ret.sprintf("%f", lp / rp);
}
}
else
{
ret = "Error";
}
}
return ret;
}
QString QCalculatorDec::calculate(QQueue<QString>& exp)
{
QString ret = "Error";
QStack<QString> stack;
while( !exp.isEmpty() )
{
QString e = exp.dequeue();
if( isNumber(e) )
{
stack.push(e);
}
else if( isOperator(e) )
{
QString rp = !stack.isEmpty() ? stack.pop() : "";
QString lp = !stack.isEmpty() ? stack.pop() : "";
QString result = calculate(lp, e, rp);
if( result != "Error" )
{
stack.push(result);
}
else
{
break;
}
}
else
{
break;
}
}
if( exp.isEmpty() && (stack.size() == 1) && isNumber(stack.top()) )
{
ret = stack.pop();
}