day01***************************************
qt是C++的库 也包含有windows库
哪些类 实现哪种方法
qwidget:所有窗口的父基类
qdialog:只有关闭按钮 无最大最小化
qmainwondow:有菜单 工具
应用程序类:Qappliaction a(argc,argv); return a.exec();
1只有一个应用程序类对象
2进行消息循环,捕捉处理事件a.exec() 里封装了while(getmessage(&msg/*out*/))
Q_Object:如果使用qt的信号槽机制, 必须添加该宏
.pro里别加注释 QT模块有core gui widgets network sql 会生成makefile
坐标体系:x轴向右递增 y轴向下递增
QT回收机制:以下2点必须同时满足才能自动回收
1类直接或间接从QObject派生
2创建对象的时候,需要需要给对象指定父类
自定义控件:自定义控件后再脱控件再提升
为什么得自定义控件?因为一般来说控件都是集成于Qwidget,都可以用Qwidget的全局函数(::的形式)这些函数基本上都是通用的比如:
setIcon、setText等,这些函数只能进行简单的设置,因为是通用的。如果以直接脱进去的方式或new的方式创建一个控件而不写一个
自定义控件 那么就只能使用这些全局函数进行简单的设置。若想要复杂的设置比如平铺一张图片,这就需要自定义控件,在控件中虚
函数重写 而且这样的好处是很清晰不乱
1. 自定义一个类, 从标准控件类直接或间接派生
2. 在UI上拖放一个控件, 在该控件上, 右键 --> 提升为...
3. 在打开的对话框窗口中, 添加要提升的类名 --> 添加 --> 提升
原则:将父类变子类;例如自定义的类是从QPushButton派生的子类, 那么该类就只能提升QPushbutton类型的控件:
mybutton::mybutton(QWidget *parent) : QPushButton(parent)即定义一个mybutton类从QPushButton派生
eg:自定义一个类label 右键添加一个新文件c++class 从qwidget派生(从哪派生无所谓,最终还是得改)
该lable的.h中#include<qlable> 把public qwidget改成public qlable
窗口相关函数:
窗口大小:int width() const;int height() const;void resize(int w, int h);
void setFixedHeight(int h);void setFixedSize(int w, int h);void setFixedWidth(int w);
获取窗口标题:QString windowTitle() const;
设置窗口标题:void setWindowTitle(const QString &);
设置窗口图标:void setWindowIcon(const QIcon & icon);
获取窗口图标:QIcon windowIcon() const;
移动窗口:void move(const QPoint &);void move(int x, int y);
信号槽:
1.需要两个对象: 可以相同可以不同:信号发出者;信号接受者
2. 需要让两个对象产生关系: connect函数连接两个QObject对象,只是注册
3. connect函数的使用:类指针指向本类的某个信号事件 类指针指向本类的一个普通函数
connect(Sender, &Sender::signal, Rerever, &Rerev::slot);
connect(ui->pushButton,&QPushButton::clicked, ui->spinBox, &QSpinBox::setValue);
参数:对象 对象的信号 信号接收者 槽函数(信号的处理函数)
自定义信号:
1. 返回为void,可以传参(不愧为信号),小心函数重载不能一一对应的问题
2. 只有函数声明, 没有函数定义
3. 定义信号的时候需要使用关键字: signals
4. 信号可以重载
5. 自己发信号: emit
eg:
signals:
void hasNespaper();
槽函数: -- 跟信号对应的一个函数
1. Qt5中类的成员函数, 全局函数, 静态函数, lambda表达式
2. 没有返回值: void
3. 可以重载
4. 槽函数的参数需要跟信号的参数一一对应:
即:connect(print, &QPushButton::clicked, paper, &Newspaper::hasNespaper1);
而hasNespaper1是一个重载函数 所以必须使用函数指针解决:
void (Newspaper::*mysignal)(QString, QString) = Newspaper::hasNespaper1;
lambda表达式:
匿名函数: [] -- 匿名函数的开始, () -- 参数列表, {} -- 函数体
[] 中添加的符号:
什么也不加: 不能使用匿名函数外部的任何数据
= : 使用外部数据的时候, 传递方式为值传递
& : ..............., 传递方式为引用
有名函数: int aa(int);
所以 connect(print, &QPushButton::clicked, this, &Widget::slotPrint);
可以写成:
connect(print, &QPushButton::clicked, this, [=]()
{
paper->send();
});
QMainWindow:
菜单栏:
1一个窗口只允许有一个菜单栏 -- QMenuBar
2菜单项:QMenu 手动添加动作: action就是那些另存为 保存 打开什么的
QMenu* menu = new QMenu(this); menu->addAction(ui->actionAa);
QAction *save = addAction(..., ...);即添加一个save的action???????????????????????????????
3动作QAction 信号: void triggered(bool checked = false)即connect时候用的第二个参数
工具栏:
1一个窗口可以有多个工具栏 -- QToolBar
2添加工具栏:QMainWindow::addToolBar
3设置停靠位置:void setAllowedAreas(Qt::ToolBarAreas areas)
4其他:是否浮动: void setFloatable(bool floatable);是否能够移动: void setMovable(bool movable)
状态栏:都不常用
---------------------------
手动添加按钮:QPushButton* btn = new QPushButton("quit", this);
connect典型用法: connect(btn, &QPushButton::clicked, this, &Widget::close);
在工具栏中添加按钮:ui->mainToolBar->addWidget(new QPushButton("Hello, toolBar"));
QAction添加图标:ui->actionSaveAsABC->setIcon(QIcon(":/acb/Image/heart.png"));
显示汉字一般都是用Qlabel
day02***********************************************************
QDialog
模态:dlg.exec在connect的lambda表达式中常用 密码界面好像不用这个,密码界面自定义了qdialog控件
窗口显示之后, 不能对其他窗口进行操作;窗口显示之后, 代码停止向下执行, 窗口关闭, 代码继续向下执行
非模态:dlg.show
窗口显示, 不影响代码的执行
由于非阻塞,若定义成类对象一旦lambda表达式执行完就立即析构,所以定义成类指针
窗口关闭, 释放动态分配的内存:setAttribute(Qt::WA_DeleteOnClose) [55]
提示(标准)对话框:
类名: QMessageBox
静态成员函数:critical information question warning
int ret = QMessageBox::critical(this, "错误", "这是一个错误",
QMessageBox::Yes | QMessageBox::No,
QMessageBox::No);//标题 显示内容 按钮 自动选定按钮
返回值:QMessageBox::Ok/Cancel/Close/Yes/No
if(ret == QMessageBox::No){QMessageBox::aboutQt(this, "++++");}
文件对话框:
类名: QFileDialog
静态成员函数:getOpenFileName;getSaveFileName;getExistingDirectory
QString str = QFileDialog::getOpenFileName(this, "打开文件", "E:\\","Pic (*.txt)");
//标题是打开文件 选定位置是E盘根目录 类型格式限定为txt
颜色对话框:
字体对话框:
Widget总结:
要么脱 要么new
button类:QGroupBox里面放单选按钮QRadioButton典型应用是性别男女 里面放QCheckBox复选按钮想想小正方形点击则有√
容器类:
QToolBox想想QQ中的分组里面也是多个QWidget的page
QStackedWidget可有多个QWidget的page 通常配合按钮 用setCurrentIndex(1)进行翻页
QTabWidget想想浏览器里面是QWidget
QToolButton即mainwindow里的button
QComboBox下拉框 添加下拉内容用addItem
QTextEdit文本编辑框 QTextEdit,QPlainTextEdit,这些是用toPlainText()来获取文本内容,而QLineEdit,QLabel,QTextBlock等是用text()来获取内容。
QSpinBox里面两个小箭头 可改变数值大小 注意其信号函数是一个重载函数 connect的时候得用函数指针
QSlider音量条
封装自己的控件:跟自定义控件一样
先确定从QWidget派生,创建smallwidget类:class SmallWidget : public QWidget
然后再ui中脱控件 组合自己的类
在使用的时候右键提升
注意右键添加文件的区别 自定义控件是C++没有界面文件 而添加QT设计师界面类会生成额外生成一个界面
Qlabel功能强大可显示文本 动态图 图片 和html
显示图片:QPixmap pix(":/Image/Luffy.png");
pix.scaled(100, 100);
ui->pic->setPixmap(pix.scaled(100, 100));
定时器典型用法:
QTimer* timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, [=]()
{
static int num = 0;
ui->lcdNumber->display(++num);
});
timer->start(10);
day03***************************************************
绘图类:画家qpainter和他的工具画笔qpen、画刷qbrush、设置字体qfont
QPainter p(this);作用: 可以使用绘图类在绘图设备this上画图
p.drawPixmap画背景图
p.drawLine(QPoint(100, 100), QPoint(400, 400));画线
p.drawEllipse(QPoint(250, 250), 100, 100);画圆
p.drawText(50, 100, "让编程改变世界!");输出文本
QPen pen;设置画笔 画笔设颜色宽度样式
pen.setColor(Qt::green);pen.setWidth(5);pen.setStyle(Qt::DashLine);
p.setPen(pen);画笔设给画家 画家设背景 图形 文字
QBrush brush(Qt::red, Qt::CrossPattern);设置画刷
p.setBrush(brush);
注意设置字体是在构造函数中而不是paintEvent函数中:
QFont font("华文彩云", 32, 75, true);
this->setFont(font);
绘图类的一些函数:
pixmap加载图片:pix.load("E:\\Image\\8.jpg");
画点: void drawPoint(int x, int y)
画线: void drawLine(const QPoint & p1, const QPoint & p2)
画圆: void drawEllipse(int x, int y, int width, int height)
画矩形: void drawRect(int x, int y, int width, int height)
写文字: void drawText(int x, int y, const QString & text)
画背景图:
void drawImage(const QPoint & point, const QImage & image)
void drawPixmap(int x, int y, const QPixmap & pixmap)
p.drawPixmap(0,0,this->width(),this->height(),QPixmap("E:\\Image\\1.jpg"));
多边形: void drawPolygon(const QPolygon & points, Qt::FillRule fillRule = Qt::OddEvenFill)
上面几乎所有设置都是在paintevent函数中
绘图设备:QPaintDevice类是实际的绘制设备的基类.QPainter能够在QPaintDevice子类上进行绘制,
如QWidget,QImage,QPixmap,QGLWidget,QGLPixelBuffer,QPicture,QPrinter
主要是重写protected中的paintEvent函数
paintEvent 不需要用户调用, 窗口需要刷新的时候自动被调用:
1. 窗口显示的时候 2. 最大化最小化的时候 3. 一部分覆盖重新显示的时候 4. 手动刷新: update() : QWidget
QWidget:
必须 重写窗口的事件处理函数 void paintEvent(QPaintEvent*)所有的画图操作必须在paintEvent函数中完成
给画家类指定画图设备为当前窗口: QPainter p(this)
手动刷新窗口函数:update()
QPixmap:是个抽象的画 需要画家调用才能显示出来p.drawPixmap
专门为图像在屏幕上的显示做了优化, 在不同平台拥有相同的显示效果
依赖于平台
加载图片:
在构造函数中加载图片: QPixmap pix(图片路径);或QPximap pix; pix.load(图片路径);
在Qpixmap上画图:
构造对象时指定画布的大小: QPixmap pix(width, height)
给画家类指定画图设备: QPainter p(&pix)
使用 QPainter 类调用其画图函数完成画图
画图完成后, 保存图片: pix.save(保存路径);
QImage:是个抽象的画 需要画家调用才能显示出来p.drawImage
使用独立于硬件的绘制系统, 专门为图像的像素级访问做了优化
可以在多线程中使用
可以修改图片中的任何一个像素值
不依赖于平台, 可用于图片的传输
加载图片:与qpixmap一样
在构造函数中加载图片: QImage img(图片路径);
QImage img;
img.load(图片路径);
蝴蝶问题:
同窗口重绘,需要重写protected中很多的事件函数:paintEvent、鼠标按下、鼠标移动、进入窗口瞬间......
qdialog 带ui 直接放按钮 connect按键则显示模态窗口 特点是新窗口不关就回不到原来的窗口 有阻塞
非模态 不会阻塞 而一闪而过 所以用指针 引出内存泄露问题 用设置属性解决
添加一个新的dialog。 new出一个新的 则有输出确实被析构了
再加一个按钮提示对话框 需要qmessagebox类只用静态成员函数
connect点击则调qmessagebox的静态成员函数
--------
文件对话框类 也是只是用静态成员函数
connect
----------
建立一个window
拉一个widget最大化 不要布局
再拉一个frame
再拉一个groupbox 一般配合radiobutton 性别男女
toolbox 我的好友那个抽屉容器 其父亲是qframe 可加边框 ui指针取抽屉的item
tabwidget 默认2个tab页 右键插入页
stackwidget 堆叠窗口:控制窗口切换
-------
qtoolbutton 只能通过代码添加 new出来一个button 再new出来一个menu对象 创建3个action对象aa bb cc
菜单设置给button
qradiobutton 单选按钮 互斥的
checkbox 爱好 不互斥的 可选多个
-------
combobox 双击 additem
lineedit 只显示一行
---------------
布局:
创建QMainwindow文件 下面会有四个对象有一个widget
再拉一个widget让他成为最大的窗口 再把按钮拖进去 点击右上角那个主widget下面的widget下的垂直水平布局
一般情况下 先拉进去一个最大的widget 然后再拉进去小的widget 将小的控件放到小的widget中
只有在widget中才能用弹簧 和 网格布局
------------
自定义控件(类):即把一个widget和里面的东西都封装成一个类
先添加新文件QT设计师类 由于自定义窗口比较简单而且是widget 所以必须定义一个widget类且带UI
在UI中构造封装 且写封装函数(真正的难点,需要connect 和定义接口)
使用自定义控件: 先拖一个widget(必须是widget) 右键提升为 提升类名称 全局包含 添加 提升 即可。执行就可以看到了
注意:只要添加一个带UI的新类 就会从widget继承 所以当添加按钮类时 得改成从按钮派生??????????
-----------
建立资源文件:
右键添加新文件 resource 起名称 生成.qrc 添加 写一个前缀/ 点击添加文件 新建一个文件夹image
setIcon(QIcon(":/Image/*.png"));
*********************************************************************
mainwindow为主窗口 用dialog不允许改变大小
添加一个dialog类带ui 选没有按钮的dialog类 做登录界面 设置固定大小
在log类中写代码setecomode 按键都转到槽
登录:获取用户名 密码 判断 QMessageBox......
main中 定义login类
--------------
label
-----------------
时间:跟中断非常相似
F4进入mainwindow父类中 在protected下的打桩虚函数painEvent
用Qpainter对象画图
-----------------------------------
蝴蝶:
widget.h中 protected事件 private两个图片 构造函数初始化加载图片
事件函数中画图.........
看widget的protected事件函数都有哪些
---------------------
day05***********************************************
数据库操作:
类名:QSqlDataBase base
QSqlDatabase base = QSqlDatabase::addDatabase("QMYSQL");
base.setHostName("192.168.22.56"); // 主机IP
base.setPort(3306); // 设置端口
base.setUserName("root"); // mysql登录用户名
base.setPassword("root"); // mysql登录密码
base.setDatabaseName("itcast"); // 使用的数据库的名字
base.open()//打开数据库
开启事务:QSqlDatabase::transaction() 设置一个点, 如果发生了错误操作, 该点即为还原点
状态回滚: QSqlDatabase::rollback() 撤销操作, 回到设置事务的点
提交状态: QSqlDatabase::commit()提交操作(从设置事务的点到当前)
查询数据库:
类名: QSqlQuery query
query.exec("select * from people");
批量插入:QStringList agelist;
agelist << QString::number(45) << QString::number(40)
<< QString::number(35) << QString::number(23);
query.bindValue(":age", agelist);
while(query.next()){//打印字段的值
qDebug() << query.value(0).toInt()//打印id
<< query.value(1).toString()//打印name
<< query.value(2).toInt();}//打印age
数据库模型:
类: QSqlTableModel model
QSqlTableModel *model = new QSqlTableModel(this);
model->setTable("student"); // 设置数据库表名
model->select();// 查询数据库
ui->tableView->setModel(model); // 将模型设置给视图
model->setEditStrategy(QSqlTableModel::OnManualSubmit);// 设置提交方式 -- 手动提交
connect(ui->submit, &QPushButton::clicked, this, [=]()
{
// 提交
model->submitAll();
});
********************************************************
qlabel设置图片setPixmap scaled
qlineedit设置文字setText 取内容text返回QString
弹警告框QMessageBox::information(this, "info", "输入的用户名密码错误, 请重新输入!");
Stacked Widget可以有很多widget页面(page)
*********************************************************
Json:json view网站可以直接打开
{
"name":"zhang3",
"age":18,
"id":100,
"girls":["marong","marong1","marong2"],
"salary":2000,
"object_child":{}
}
Cjson开源库 用于解析
查询数据库 包装后给 前端发过去
mfc===========================================================================
一个最简单的mfc程序 初始化消息机制
mfc+鼠标点击消息机制
基于窗口框架类:app+窗口框架类 create消息机制调用OnCreate函数
基于对话框类:app+对话框类 create消息机制调用OnInitDialog函数
基于单文档类:app+主框架类+视图类+doc类
添加资源关联类 生成.h .cpp文件 其中.h文件中会有具体的关联:enum { IDD = IDD_DIALOG1 };
添加拖控件 类多一个属性 .cpp中DoDataExchange中多了一个宏函数
下拉框combobox 树控件CTreeCtrlDlg 报表CListCtrl CTabCtrl
快速浏览mfc固定套路:先打开资源视图看都有什么资源(类) 再看都有什么属性与图对应起来 再看Oinit函数都干了什么
mfc精髓是自定义消息 postmassage手动发送自定义消息到消息队列中 待主框架类中消息处理
-------------
窗口:客户区和非客户区
一个 Windows 应用程序至少要有一个窗口,称为主窗口。
句柄:资源即对应一个唯一的句柄 一个窗口对应一个句柄
消息:WM开头的是windows的标准消息
消息队列:一旦起一个进程,os就会创建一个消息队列 os则捕捉被触发的消息 放到消息队列中 再通过窗口过程函数(消息处理函数)处理消息
WinMain是Windows程序的入口点函数,与DOS程序的入口点函数main的作用相同
窗口过程函数LRESULT CALLBACK WinProc
创建一个mfc:新建项目 Win32 Win32项目(基于UI的) windows应用程序、空项目 完成
右键添加新建项hello.c 添加头文件 定义WinMain函数 __stdcall设置参数入栈是从右向左
创建一个mfc:新建项目 Win32 Win32项目(基于UI的) windows应用程序、空项目 完成
右键添加.h .cpp
右键属性MFC的使用 改成别是window 动态的好 因为占内存少
创建新项目 MFC MFC应用程序 单文档 MFC标准 DLL中使用MFC 自动生成4个类 完成
运行跟记事本差不多
一个最简单的mfc程序:
看一怀去意的图,得创建两个类CFrameWnd框架窗口类和CWinApp应用程序类。
1窗口类必须写构造函数,构造里this->Create(NULL, TEXT("你好, Mfc"))创建窗口;
**********也就是说一般要显示的东西的初始化都写在相应的构造函数里 而且这个函数里一般都有create初始化
2应用程序类重写InitInstance函数(作用类似于main函数) 里面MyFram* frame = new MyFram创建框架,然后
对框架进行更新和设置显示:
frame->UpdateData();更新和显示窗口
frame->ShowWindow(SW_SHOWNORMAL);
3别忘了定义一个全局的应用程序类对象
一个最简单的mfc程序+消息机制:
在上面的基础之上,添加3个地方:
1.h中在窗口框架类中声明消息映射即消息处理函数:DECLARE_MESSAGE_MAP()
afx_msg void OnLButtonDown(UINT, CPoint); // 鼠标左键按下对应的处理函数
2.cpp中 全局区开始消息映射:
BEGIN_MESSAGE_MAP(MyFram, CFrameWnd)
ON_WM_LBUTTONDOWN() // 映射入口
END_MESSAGE_MAP()
3.实现消息函数OnLButtonDown(UINT, CPoint);
----------------
基于窗口框架类:
自动创建一个类似的记事本时:学MFC要站在MFC角度思考问题
依然是 app类中有InitInstance函数为入口 窗口框架类中重写OnCreate函数初始化。
窗口框架类:墙 WM_CREATE消息 OnCreate(LP....)
afx开头的都是全局函数 afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
窗口框架类中的create的函数一旦调用(编译器内部调的,create调用时机:在窗口创建完成之后,但还没显示之前。
基于窗口的类都可以对OnCreate函数进行重写),会对OS发出WM_CREATE消息,该消息对应一个处理函数afx_msg int OnCreate(LP....)
OS把它放到消息队列,一旦取出来的时候,要么给默认处理函数执行默认处理,要么自己处理,得添加消息映射(上面的步骤2)
在处理函数OnCreate(LP....)中各种设置.......
视图类:墙纸 WM_PAINT消息 OnDraw
视图得不断刷新,OS会发出WM_PAINT消息,该消息对应的处理函数是OnPaint。但是自动生成的代码中没有OnPaint(虚)函数,只有OnDraw函数
其实父类的OnPaint函数中调用OnDraw(虚函数)函数 这个虚函数重写发生多态调用子类的OnDraw函数
OnDraw必须得重写,除非你不想显示东西,但它不是消息处理函数,它只是消息处理函数的一部分。窗口的刷新通过多态(调用重写函数)实现的
当然也可以在子类中重写OnPaint函数,覆盖了父类的OnPaint函数。不过这样麻烦一切都得自己写
给一个窗口添加一个事件:找到类视图 右键属性 选择消息 点一下则自动在三个位置增加了代码
为什么mfc中有宽字节???
QT中用的是unicode的utf8编码:字符占一个字节 汉字占三个字节
vs中用的是gbk编码:字符占一个字节 汉字占两个字节 (文件->保存高级选项能设置字体编码格式)
重点来了:怎样保存一个汉字?
vs下 char c[2]="中" 但是这样不好访问 所以就有了wchar_t
char*前面加L 即把char*转换为宽字节 eg:wchar_t *pt=L"hello world" 在mfc中默认是unicode 所以得转为宽字节
Windows字符集
1. 多字节字符集 -- 1个字符 1byte == 8bit
1> char* p = "hello, world";
2. 宽字节字符集 -- 1个字符2byte == 16bit
1>. 存放中文, 拉丁, 棒子, 鬼子
TEXT会根据编码格式的不同自动变化 #define中的##是连接的意思
day02****************************************************
模态对话框:基于对话框(3个类):CAboutDlg 程序名App 程序名Dlg
dialog.cpp中首先完成应用程序类中的InitInstance函数的编写:return TRUE应用程序会继续向下执行;return FALSE应用程序直接退出
所以返回false
注意基于对话框的应用程序 而是在OnInitDialog函数里(窗口框架类是OnCreate)。
OnInitDialog调用时机是:窗口初始化完成且窗口即将显示之前
Qt中却可以在构造中初始化控件:有this指针和setup.....
.rc资源文件中可以脱控件 窗口通过enum里的IDD关联代码
脱控件 右键属性 事件 BNCLICKED addbuttonclicked 或 直接双击 杂项中的id最好改一下
若点击对话框中的一个按钮想弹出另一个新的对话框则必需得:
1. 资源视图中添加对话框资源:.rc右键添加资源 选dialog 新建 脱进去控件 ;
再右键添加类 取名字MyDlg 选基类 完成后会多,出MyDlg的.c和.h文件
2. 给对话框资源关联一个类
3. 使用之前先包含头文件
4. 创建对象
非模态对话框:
秉承了QT中非模态对话框的传统:非模态变量不能是局部变量得最好添加到成员属性中
仍然得添加资源
还得在主窗口的构造函数中creat初始化:m_dlg.Create(IDD_DIALOG1, this);
mfc中的create是初始化的意思
static text上显示一张图片:
只要有事件 先改杂项中的id;因为id是idcstatic的是不能处理消息的
想在程序中操作一个控件必须先关联变量。so 显示图片得先关联变量:右键添加变量:private control类别 起个名字
相应的代码2个地方发生了改变:头文件的类中多了一个属性CStatic m_pic;。还有.cpp的DoDataExchange中多了一个宏函数
*************类通过enum里的IDD关联代码 而控件的关联变量通过多个属性,DoDataExchange中多了一个宏函数
关联后就在OnInitDialog中初始化:
先右键添加资源 导入 .bmp图片
再添加一个CBitmap属性m_bitmap。m_bitmap.LoadBitmapW(IDB_BITMAP1);加载图片
最后m_pic.SetBitmap((HBITMAP)m_bitmap);
密码登陆:
如果想操作编辑框里的内容(往里面设置内容)必须得关联变量,编辑框控件一般绑定value类别,因为框中的东西是字符串......
user设置为张三 密码设为张三疯
因为是value所以变量和数据间交换得手动更新updatedata
可以对一个button进行复杂的关联操作,虽然麻烦但是可以复杂的操作。eg在button上显示一个图
但是不实用所以直接双击就可以添加事件了
下拉框combobox:
Combobox拖进去 右键属性 在行为里的data里直接写南帝北丐....用分号分割 外观Type选项simple/droplist
或右键添加变量 然后初始化中就是增删改查
因为得取编辑框内容 所以也得关联
报表CListCtrl:
CLISTctrl 外观改成report报表模式
依然是关联control类别 在OnInitDialog中:初始化表头、添加数据、属性设置:加网格 整行选中参数是DW类型的宏
(非常象嵌入式中的寄存器设置)
树控件CTreeCtrlDlg:
右键属性 has buttons/line;lines at root;
仍是关联变量 类别是control 在OnInitDialog中 初始化
添加数据 插入节点返回该节点的句柄
显示图片:得添加类比较复杂 秉承了不能是成员变量的特点。
先在.h中添加CImageList属性;资源中添加图片;在create初始化:向属性中添加图片:m_image.Create(32, 32, ILC_COLOR32, 4, 4);
然后......
要求点击小节点会显示其内容:点击小节点的属性、事件selectchange 直接Add进代码。
CTabCtrl即tab页浏览器那个
用封装好的类CTabSheet。class CTabSheet : public CTabCtrl
凭直觉 猜
关联添加变量(添加到的是最初的那个tabsheetdlg.cpp中) control类别 在变量类型上填上CTabSheet 与QT中提升一样
添加2个dialog资源(去掉border 设置style为child) 再关联类(生成.cpp .h文件) 把这两个类包含到.cpp中
用封装好的函数初始化tab页
什么时候添加变量关联? 要操作这个控件 与QT中提升一样
什么时候添加资源关联类? 一个窗口包含有另外的窗口
......
关联类会生成.h .cpp文件 其中.h文件中会有具体的关联:enum { IDD = IDD_DIALOG1 };
在这个类资源上添加各种控件(添加变量关联)
添加变量会在两个地方发生变化 类中会多一个属性 .cpp中DoDataExchange中多了一个宏函数
先打开资源视图看都有什么资源(类) 再看都有什么属性与图对应起来 再看Oinit函数都干了什么
day03**********************************************************
基于单文档类:
messagebox(cstring)用于打印调试
单文档的mfc程序(没有onInitDialog函数) 不使用传统的工具栏 生成4个类
设置图标:时机是初始化之后显示之前 很明显是create函数
mainfrm的OnCreate函数里设置图标,用的是windows的api:HICON hIcon = AfxGetApp()->LoadIconW(IDI_ICON2);
图标是ico格式 添加资源导入记住资源id
setclasslong(this->m_hwnd,)
第一个参数:窗口的资源标示(句柄)m_hwnd
设置窗口大小:
仍是create函数里
Movewindow 或 centerwindow
设置窗口标题:
去文档类(看类视图里有Doc)设置OnNewDocument函数中
SetTitle
登录对话框:
得有对话框资源 添加资源dialog ui界面直接修改标题......
先关联类dialog(生成.cpp .h文件) 再关联dialog窗口中的l inedit变量(多出CString m_user;CString m_pwd;属性 还有双击button控件)
因为得初始化dialog中的控件 但是里面没有OninitDialog 所以得手动添加:
右键属性->消息->重写->OninitDialog 在.cpp中oninitdialog里面:m_user=_T("mike");m_pwd=....
亦或者使用类向导 类向导是个非常吊的东西
登录对话框得先显示所以得在saleSystem.cpp中的SystemApp类中的InitInstance中创建login对象 显示模态对话框(会阻塞)
通过判断模态对话框的返回值INT_PTR nResponse = login.DoModal(); 决定 登录还是退出
回到login.cpp中继续:双击按钮.......
静态拆分窗口:拆的是视图(墙纸) 视图在框架窗口上(墙)
在Mainfrm中 静态拆分窗口 .....怎么设置的???....在框架类Oncreate执行期间被调用OnCreateClient
所以重写给出来的接口OnCreateClient 但是里面没有OnCreateClient 所以得手动添加(同514)
即框架上原来的窗口不用了 用一个拆分的窗口
别忘了屏蔽默认处理
添加两个窗口:
添加类 MFC CTreeView基类 完成(多出来.cpp .h) 同样添加CFormView基类
把这两个窗口类的名字填到上面的静态拆分窗口里
即可显示
左侧树窗口/右侧显示窗口:RUNTIME_CLASS(CSelectView) RUNTIME_CLASS(CDisplayView)
由于不是基于对话框 所以没有Oninitdialog
所以有类似的得右键属性重写OnInitialUpdata 调用时机是视图窗口创建之后 显示之前
1234
点击图标 右侧显示会变:
右键 属性事件 以=开头的都是控件的事件 add进代码里:
switch case不能用于字符串判断 比起if else还是有局限性
如何通知外面已经切换了:则自定义wm消息 仍到消息队列中
消息定义在框架类上 因为5个视图都在框架窗口上
先在mainfrm.h中 自定义消息:#define NM_A (WM_USER+100)
实现自定义消息映射:
1.h中在窗口框架类中声明消息映射即消息处理函数:DECLARE_MESSAGE_MAP()
afx_msg LRESAULT OnMyChange(WPARAM wParam, LPARAM lparam);
2.cpp中 全局区开始消息映射:
BEGIN_MESSAGE_MAP(MyFram, CFrameWnd)
ON_MESSAGE(NM_A,OnMyChange) // 映射入口
END_MESSAGE_MAP()
3.右键....没看清....实现消息函数OnLButtonDown(UINT, CPoint);
由于是自定义消息,需要手动发送自定义消息到消息队列中:PostMessage();写在if else中
但是得用windows的postmessage其第一个参数是框架窗口的句柄,第二个参数是消息NM_A
用windows的postmessage原因是 当前视图里没有nm_a消息
最后实现OnMyChange(WPARAM wParam, LPARAM lparam)
这就是mfc的精髓所在
个人信息的右侧:添加资源dialog id改名为user 去掉border 设置style为child
添加类 基类选cfromview
在Mainfrm中 自定义消息处理函数中:
删除原来的视图第一行第2列
使用m_spliter重新创建一个视图
获取视图对象
初始化视图资源
将刚添加的视图设为活动的视图
刷新窗口拆分类中的布局(显示新创建出来的视图)
菜单操作:重点是怎样给菜单项添加消息
资源视图menu里是菜单资源.......
改id 右键添加事件处理程序 消息类型:commamd 类列表(在哪个窗口处理):cmainframe
会在MainFrm.cpp中的3个位置自动添加一些东西
在展开的函数里postmessage.......
-------------------------------------
无非就是:添加资源(属性中body style id) 关联类(关联id)
主的.cpp中定义应用程序的类行为:
应用程序类中有重写的main入口 app构造 有读配置参数 连接数据库 和关于app
框架类主要 窗口的split
一个非常吊的API函数:CWnd *GetDlgItem(IDC_CHECK_LineEdit);可以操作返回的句柄操作那个lineedit
从资源视图开始找
工具 sqlplus worksheet 执行
commit;
增删改除 不难 量大 熟练度的问题
描述在MFC中如何使用ODBC访问Mysql数据库?
1. 安装Mysql的odbc驱动
2. 使用向导添加数据源
3. 创建MFC单文档/多文档视图应用程序, 添加数据库支持, 选择数据源, 给数据源中的数据库表绑定记录集类
4. 通过绑定的记录集对象访问对应的数据库]
qt是C++的库 也包含有windows库
哪些类 实现哪种方法
qwidget:所有窗口的父基类
qdialog:只有关闭按钮 无最大最小化
qmainwondow:有菜单 工具
应用程序类:Qappliaction a(argc,argv); return a.exec();
1只有一个应用程序类对象
2进行消息循环,捕捉处理事件a.exec() 里封装了while(getmessage(&msg/*out*/))
Q_Object:如果使用qt的信号槽机制, 必须添加该宏
.pro里别加注释 QT模块有core gui widgets network sql 会生成makefile
坐标体系:x轴向右递增 y轴向下递增
QT回收机制:以下2点必须同时满足才能自动回收
1类直接或间接从QObject派生
2创建对象的时候,需要需要给对象指定父类
自定义控件:自定义控件后再脱控件再提升
为什么得自定义控件?因为一般来说控件都是集成于Qwidget,都可以用Qwidget的全局函数(::的形式)这些函数基本上都是通用的比如:
setIcon、setText等,这些函数只能进行简单的设置,因为是通用的。如果以直接脱进去的方式或new的方式创建一个控件而不写一个
自定义控件 那么就只能使用这些全局函数进行简单的设置。若想要复杂的设置比如平铺一张图片,这就需要自定义控件,在控件中虚
函数重写 而且这样的好处是很清晰不乱
1. 自定义一个类, 从标准控件类直接或间接派生
2. 在UI上拖放一个控件, 在该控件上, 右键 --> 提升为...
3. 在打开的对话框窗口中, 添加要提升的类名 --> 添加 --> 提升
原则:将父类变子类;例如自定义的类是从QPushButton派生的子类, 那么该类就只能提升QPushbutton类型的控件:
mybutton::mybutton(QWidget *parent) : QPushButton(parent)即定义一个mybutton类从QPushButton派生
eg:自定义一个类label 右键添加一个新文件c++class 从qwidget派生(从哪派生无所谓,最终还是得改)
该lable的.h中#include<qlable> 把public qwidget改成public qlable
窗口相关函数:
窗口大小:int width() const;int height() const;void resize(int w, int h);
void setFixedHeight(int h);void setFixedSize(int w, int h);void setFixedWidth(int w);
获取窗口标题:QString windowTitle() const;
设置窗口标题:void setWindowTitle(const QString &);
设置窗口图标:void setWindowIcon(const QIcon & icon);
获取窗口图标:QIcon windowIcon() const;
移动窗口:void move(const QPoint &);void move(int x, int y);
信号槽:
1.需要两个对象: 可以相同可以不同:信号发出者;信号接受者
2. 需要让两个对象产生关系: connect函数连接两个QObject对象,只是注册
3. connect函数的使用:类指针指向本类的某个信号事件 类指针指向本类的一个普通函数
connect(Sender, &Sender::signal, Rerever, &Rerev::slot);
connect(ui->pushButton,&QPushButton::clicked, ui->spinBox, &QSpinBox::setValue);
参数:对象 对象的信号 信号接收者 槽函数(信号的处理函数)
自定义信号:
1. 返回为void,可以传参(不愧为信号),小心函数重载不能一一对应的问题
2. 只有函数声明, 没有函数定义
3. 定义信号的时候需要使用关键字: signals
4. 信号可以重载
5. 自己发信号: emit
eg:
signals:
void hasNespaper();
槽函数: -- 跟信号对应的一个函数
1. Qt5中类的成员函数, 全局函数, 静态函数, lambda表达式
2. 没有返回值: void
3. 可以重载
4. 槽函数的参数需要跟信号的参数一一对应:
即:connect(print, &QPushButton::clicked, paper, &Newspaper::hasNespaper1);
而hasNespaper1是一个重载函数 所以必须使用函数指针解决:
void (Newspaper::*mysignal)(QString, QString) = Newspaper::hasNespaper1;
lambda表达式:
匿名函数: [] -- 匿名函数的开始, () -- 参数列表, {} -- 函数体
[] 中添加的符号:
什么也不加: 不能使用匿名函数外部的任何数据
= : 使用外部数据的时候, 传递方式为值传递
& : ..............., 传递方式为引用
有名函数: int aa(int);
所以 connect(print, &QPushButton::clicked, this, &Widget::slotPrint);
可以写成:
connect(print, &QPushButton::clicked, this, [=]()
{
paper->send();
});
QMainWindow:
菜单栏:
1一个窗口只允许有一个菜单栏 -- QMenuBar
2菜单项:QMenu 手动添加动作: action就是那些另存为 保存 打开什么的
QMenu* menu = new QMenu(this); menu->addAction(ui->actionAa);
QAction *save = addAction(..., ...);即添加一个save的action???????????????????????????????
3动作QAction 信号: void triggered(bool checked = false)即connect时候用的第二个参数
工具栏:
1一个窗口可以有多个工具栏 -- QToolBar
2添加工具栏:QMainWindow::addToolBar
3设置停靠位置:void setAllowedAreas(Qt::ToolBarAreas areas)
4其他:是否浮动: void setFloatable(bool floatable);是否能够移动: void setMovable(bool movable)
状态栏:都不常用
---------------------------
手动添加按钮:QPushButton* btn = new QPushButton("quit", this);
connect典型用法: connect(btn, &QPushButton::clicked, this, &Widget::close);
在工具栏中添加按钮:ui->mainToolBar->addWidget(new QPushButton("Hello, toolBar"));
QAction添加图标:ui->actionSaveAsABC->setIcon(QIcon(":/acb/Image/heart.png"));
显示汉字一般都是用Qlabel
day02***********************************************************
QDialog
模态:dlg.exec在connect的lambda表达式中常用 密码界面好像不用这个,密码界面自定义了qdialog控件
窗口显示之后, 不能对其他窗口进行操作;窗口显示之后, 代码停止向下执行, 窗口关闭, 代码继续向下执行
非模态:dlg.show
窗口显示, 不影响代码的执行
由于非阻塞,若定义成类对象一旦lambda表达式执行完就立即析构,所以定义成类指针
窗口关闭, 释放动态分配的内存:setAttribute(Qt::WA_DeleteOnClose) [55]
提示(标准)对话框:
类名: QMessageBox
静态成员函数:critical information question warning
int ret = QMessageBox::critical(this, "错误", "这是一个错误",
QMessageBox::Yes | QMessageBox::No,
QMessageBox::No);//标题 显示内容 按钮 自动选定按钮
返回值:QMessageBox::Ok/Cancel/Close/Yes/No
if(ret == QMessageBox::No){QMessageBox::aboutQt(this, "++++");}
文件对话框:
类名: QFileDialog
静态成员函数:getOpenFileName;getSaveFileName;getExistingDirectory
QString str = QFileDialog::getOpenFileName(this, "打开文件", "E:\\","Pic (*.txt)");
//标题是打开文件 选定位置是E盘根目录 类型格式限定为txt
颜色对话框:
字体对话框:
Widget总结:
要么脱 要么new
button类:QGroupBox里面放单选按钮QRadioButton典型应用是性别男女 里面放QCheckBox复选按钮想想小正方形点击则有√
容器类:
QToolBox想想QQ中的分组里面也是多个QWidget的page
QStackedWidget可有多个QWidget的page 通常配合按钮 用setCurrentIndex(1)进行翻页
QTabWidget想想浏览器里面是QWidget
QToolButton即mainwindow里的button
QComboBox下拉框 添加下拉内容用addItem
QTextEdit文本编辑框 QTextEdit,QPlainTextEdit,这些是用toPlainText()来获取文本内容,而QLineEdit,QLabel,QTextBlock等是用text()来获取内容。
QSpinBox里面两个小箭头 可改变数值大小 注意其信号函数是一个重载函数 connect的时候得用函数指针
QSlider音量条
封装自己的控件:跟自定义控件一样
先确定从QWidget派生,创建smallwidget类:class SmallWidget : public QWidget
然后再ui中脱控件 组合自己的类
在使用的时候右键提升
注意右键添加文件的区别 自定义控件是C++没有界面文件 而添加QT设计师界面类会生成额外生成一个界面
Qlabel功能强大可显示文本 动态图 图片 和html
显示图片:QPixmap pix(":/Image/Luffy.png");
pix.scaled(100, 100);
ui->pic->setPixmap(pix.scaled(100, 100));
定时器典型用法:
QTimer* timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, [=]()
{
static int num = 0;
ui->lcdNumber->display(++num);
});
timer->start(10);
day03***************************************************
绘图类:画家qpainter和他的工具画笔qpen、画刷qbrush、设置字体qfont
QPainter p(this);作用: 可以使用绘图类在绘图设备this上画图
p.drawPixmap画背景图
p.drawLine(QPoint(100, 100), QPoint(400, 400));画线
p.drawEllipse(QPoint(250, 250), 100, 100);画圆
p.drawText(50, 100, "让编程改变世界!");输出文本
QPen pen;设置画笔 画笔设颜色宽度样式
pen.setColor(Qt::green);pen.setWidth(5);pen.setStyle(Qt::DashLine);
p.setPen(pen);画笔设给画家 画家设背景 图形 文字
QBrush brush(Qt::red, Qt::CrossPattern);设置画刷
p.setBrush(brush);
注意设置字体是在构造函数中而不是paintEvent函数中:
QFont font("华文彩云", 32, 75, true);
this->setFont(font);
绘图类的一些函数:
pixmap加载图片:pix.load("E:\\Image\\8.jpg");
画点: void drawPoint(int x, int y)
画线: void drawLine(const QPoint & p1, const QPoint & p2)
画圆: void drawEllipse(int x, int y, int width, int height)
画矩形: void drawRect(int x, int y, int width, int height)
写文字: void drawText(int x, int y, const QString & text)
画背景图:
void drawImage(const QPoint & point, const QImage & image)
void drawPixmap(int x, int y, const QPixmap & pixmap)
p.drawPixmap(0,0,this->width(),this->height(),QPixmap("E:\\Image\\1.jpg"));
多边形: void drawPolygon(const QPolygon & points, Qt::FillRule fillRule = Qt::OddEvenFill)
上面几乎所有设置都是在paintevent函数中
绘图设备:QPaintDevice类是实际的绘制设备的基类.QPainter能够在QPaintDevice子类上进行绘制,
如QWidget,QImage,QPixmap,QGLWidget,QGLPixelBuffer,QPicture,QPrinter
主要是重写protected中的paintEvent函数
paintEvent 不需要用户调用, 窗口需要刷新的时候自动被调用:
1. 窗口显示的时候 2. 最大化最小化的时候 3. 一部分覆盖重新显示的时候 4. 手动刷新: update() : QWidget
QWidget:
必须 重写窗口的事件处理函数 void paintEvent(QPaintEvent*)所有的画图操作必须在paintEvent函数中完成
给画家类指定画图设备为当前窗口: QPainter p(this)
手动刷新窗口函数:update()
QPixmap:是个抽象的画 需要画家调用才能显示出来p.drawPixmap
专门为图像在屏幕上的显示做了优化, 在不同平台拥有相同的显示效果
依赖于平台
加载图片:
在构造函数中加载图片: QPixmap pix(图片路径);或QPximap pix; pix.load(图片路径);
在Qpixmap上画图:
构造对象时指定画布的大小: QPixmap pix(width, height)
给画家类指定画图设备: QPainter p(&pix)
使用 QPainter 类调用其画图函数完成画图
画图完成后, 保存图片: pix.save(保存路径);
QImage:是个抽象的画 需要画家调用才能显示出来p.drawImage
使用独立于硬件的绘制系统, 专门为图像的像素级访问做了优化
可以在多线程中使用
可以修改图片中的任何一个像素值
不依赖于平台, 可用于图片的传输
加载图片:与qpixmap一样
在构造函数中加载图片: QImage img(图片路径);
QImage img;
img.load(图片路径);
蝴蝶问题:
同窗口重绘,需要重写protected中很多的事件函数:paintEvent、鼠标按下、鼠标移动、进入窗口瞬间......
qdialog 带ui 直接放按钮 connect按键则显示模态窗口 特点是新窗口不关就回不到原来的窗口 有阻塞
非模态 不会阻塞 而一闪而过 所以用指针 引出内存泄露问题 用设置属性解决
添加一个新的dialog。 new出一个新的 则有输出确实被析构了
再加一个按钮提示对话框 需要qmessagebox类只用静态成员函数
connect点击则调qmessagebox的静态成员函数
--------
文件对话框类 也是只是用静态成员函数
connect
----------
建立一个window
拉一个widget最大化 不要布局
再拉一个frame
再拉一个groupbox 一般配合radiobutton 性别男女
toolbox 我的好友那个抽屉容器 其父亲是qframe 可加边框 ui指针取抽屉的item
tabwidget 默认2个tab页 右键插入页
stackwidget 堆叠窗口:控制窗口切换
-------
qtoolbutton 只能通过代码添加 new出来一个button 再new出来一个menu对象 创建3个action对象aa bb cc
菜单设置给button
qradiobutton 单选按钮 互斥的
checkbox 爱好 不互斥的 可选多个
-------
combobox 双击 additem
lineedit 只显示一行
---------------
布局:
创建QMainwindow文件 下面会有四个对象有一个widget
再拉一个widget让他成为最大的窗口 再把按钮拖进去 点击右上角那个主widget下面的widget下的垂直水平布局
一般情况下 先拉进去一个最大的widget 然后再拉进去小的widget 将小的控件放到小的widget中
只有在widget中才能用弹簧 和 网格布局
------------
自定义控件(类):即把一个widget和里面的东西都封装成一个类
先添加新文件QT设计师类 由于自定义窗口比较简单而且是widget 所以必须定义一个widget类且带UI
在UI中构造封装 且写封装函数(真正的难点,需要connect 和定义接口)
使用自定义控件: 先拖一个widget(必须是widget) 右键提升为 提升类名称 全局包含 添加 提升 即可。执行就可以看到了
注意:只要添加一个带UI的新类 就会从widget继承 所以当添加按钮类时 得改成从按钮派生??????????
-----------
建立资源文件:
右键添加新文件 resource 起名称 生成.qrc 添加 写一个前缀/ 点击添加文件 新建一个文件夹image
setIcon(QIcon(":/Image/*.png"));
*********************************************************************
mainwindow为主窗口 用dialog不允许改变大小
添加一个dialog类带ui 选没有按钮的dialog类 做登录界面 设置固定大小
在log类中写代码setecomode 按键都转到槽
登录:获取用户名 密码 判断 QMessageBox......
main中 定义login类
--------------
label
-----------------
时间:跟中断非常相似
F4进入mainwindow父类中 在protected下的打桩虚函数painEvent
用Qpainter对象画图
-----------------------------------
蝴蝶:
widget.h中 protected事件 private两个图片 构造函数初始化加载图片
事件函数中画图.........
看widget的protected事件函数都有哪些
---------------------
day05***********************************************
数据库操作:
类名:QSqlDataBase base
QSqlDatabase base = QSqlDatabase::addDatabase("QMYSQL");
base.setHostName("192.168.22.56"); // 主机IP
base.setPort(3306); // 设置端口
base.setUserName("root"); // mysql登录用户名
base.setPassword("root"); // mysql登录密码
base.setDatabaseName("itcast"); // 使用的数据库的名字
base.open()//打开数据库
开启事务:QSqlDatabase::transaction() 设置一个点, 如果发生了错误操作, 该点即为还原点
状态回滚: QSqlDatabase::rollback() 撤销操作, 回到设置事务的点
提交状态: QSqlDatabase::commit()提交操作(从设置事务的点到当前)
查询数据库:
类名: QSqlQuery query
query.exec("select * from people");
批量插入:QStringList agelist;
agelist << QString::number(45) << QString::number(40)
<< QString::number(35) << QString::number(23);
query.bindValue(":age", agelist);
while(query.next()){//打印字段的值
qDebug() << query.value(0).toInt()//打印id
<< query.value(1).toString()//打印name
<< query.value(2).toInt();}//打印age
数据库模型:
类: QSqlTableModel model
QSqlTableModel *model = new QSqlTableModel(this);
model->setTable("student"); // 设置数据库表名
model->select();// 查询数据库
ui->tableView->setModel(model); // 将模型设置给视图
model->setEditStrategy(QSqlTableModel::OnManualSubmit);// 设置提交方式 -- 手动提交
connect(ui->submit, &QPushButton::clicked, this, [=]()
{
// 提交
model->submitAll();
});
********************************************************
qlabel设置图片setPixmap scaled
qlineedit设置文字setText 取内容text返回QString
弹警告框QMessageBox::information(this, "info", "输入的用户名密码错误, 请重新输入!");
Stacked Widget可以有很多widget页面(page)
*********************************************************
Json:json view网站可以直接打开
{
"name":"zhang3",
"age":18,
"id":100,
"girls":["marong","marong1","marong2"],
"salary":2000,
"object_child":{}
}
Cjson开源库 用于解析
查询数据库 包装后给 前端发过去
mfc===========================================================================
一个最简单的mfc程序 初始化消息机制
mfc+鼠标点击消息机制
基于窗口框架类:app+窗口框架类 create消息机制调用OnCreate函数
基于对话框类:app+对话框类 create消息机制调用OnInitDialog函数
基于单文档类:app+主框架类+视图类+doc类
添加资源关联类 生成.h .cpp文件 其中.h文件中会有具体的关联:enum { IDD = IDD_DIALOG1 };
添加拖控件 类多一个属性 .cpp中DoDataExchange中多了一个宏函数
下拉框combobox 树控件CTreeCtrlDlg 报表CListCtrl CTabCtrl
快速浏览mfc固定套路:先打开资源视图看都有什么资源(类) 再看都有什么属性与图对应起来 再看Oinit函数都干了什么
mfc精髓是自定义消息 postmassage手动发送自定义消息到消息队列中 待主框架类中消息处理
-------------
窗口:客户区和非客户区
一个 Windows 应用程序至少要有一个窗口,称为主窗口。
句柄:资源即对应一个唯一的句柄 一个窗口对应一个句柄
消息:WM开头的是windows的标准消息
消息队列:一旦起一个进程,os就会创建一个消息队列 os则捕捉被触发的消息 放到消息队列中 再通过窗口过程函数(消息处理函数)处理消息
WinMain是Windows程序的入口点函数,与DOS程序的入口点函数main的作用相同
窗口过程函数LRESULT CALLBACK WinProc
创建一个mfc:新建项目 Win32 Win32项目(基于UI的) windows应用程序、空项目 完成
右键添加新建项hello.c 添加头文件 定义WinMain函数 __stdcall设置参数入栈是从右向左
创建一个mfc:新建项目 Win32 Win32项目(基于UI的) windows应用程序、空项目 完成
右键添加.h .cpp
右键属性MFC的使用 改成别是window 动态的好 因为占内存少
创建新项目 MFC MFC应用程序 单文档 MFC标准 DLL中使用MFC 自动生成4个类 完成
运行跟记事本差不多
一个最简单的mfc程序:
看一怀去意的图,得创建两个类CFrameWnd框架窗口类和CWinApp应用程序类。
1窗口类必须写构造函数,构造里this->Create(NULL, TEXT("你好, Mfc"))创建窗口;
**********也就是说一般要显示的东西的初始化都写在相应的构造函数里 而且这个函数里一般都有create初始化
2应用程序类重写InitInstance函数(作用类似于main函数) 里面MyFram* frame = new MyFram创建框架,然后
对框架进行更新和设置显示:
frame->UpdateData();更新和显示窗口
frame->ShowWindow(SW_SHOWNORMAL);
3别忘了定义一个全局的应用程序类对象
一个最简单的mfc程序+消息机制:
在上面的基础之上,添加3个地方:
1.h中在窗口框架类中声明消息映射即消息处理函数:DECLARE_MESSAGE_MAP()
afx_msg void OnLButtonDown(UINT, CPoint); // 鼠标左键按下对应的处理函数
2.cpp中 全局区开始消息映射:
BEGIN_MESSAGE_MAP(MyFram, CFrameWnd)
ON_WM_LBUTTONDOWN() // 映射入口
END_MESSAGE_MAP()
3.实现消息函数OnLButtonDown(UINT, CPoint);
----------------
基于窗口框架类:
自动创建一个类似的记事本时:学MFC要站在MFC角度思考问题
依然是 app类中有InitInstance函数为入口 窗口框架类中重写OnCreate函数初始化。
窗口框架类:墙 WM_CREATE消息 OnCreate(LP....)
afx开头的都是全局函数 afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
窗口框架类中的create的函数一旦调用(编译器内部调的,create调用时机:在窗口创建完成之后,但还没显示之前。
基于窗口的类都可以对OnCreate函数进行重写),会对OS发出WM_CREATE消息,该消息对应一个处理函数afx_msg int OnCreate(LP....)
OS把它放到消息队列,一旦取出来的时候,要么给默认处理函数执行默认处理,要么自己处理,得添加消息映射(上面的步骤2)
在处理函数OnCreate(LP....)中各种设置.......
视图类:墙纸 WM_PAINT消息 OnDraw
视图得不断刷新,OS会发出WM_PAINT消息,该消息对应的处理函数是OnPaint。但是自动生成的代码中没有OnPaint(虚)函数,只有OnDraw函数
其实父类的OnPaint函数中调用OnDraw(虚函数)函数 这个虚函数重写发生多态调用子类的OnDraw函数
OnDraw必须得重写,除非你不想显示东西,但它不是消息处理函数,它只是消息处理函数的一部分。窗口的刷新通过多态(调用重写函数)实现的
当然也可以在子类中重写OnPaint函数,覆盖了父类的OnPaint函数。不过这样麻烦一切都得自己写
给一个窗口添加一个事件:找到类视图 右键属性 选择消息 点一下则自动在三个位置增加了代码
为什么mfc中有宽字节???
QT中用的是unicode的utf8编码:字符占一个字节 汉字占三个字节
vs中用的是gbk编码:字符占一个字节 汉字占两个字节 (文件->保存高级选项能设置字体编码格式)
重点来了:怎样保存一个汉字?
vs下 char c[2]="中" 但是这样不好访问 所以就有了wchar_t
char*前面加L 即把char*转换为宽字节 eg:wchar_t *pt=L"hello world" 在mfc中默认是unicode 所以得转为宽字节
Windows字符集
1. 多字节字符集 -- 1个字符 1byte == 8bit
1> char* p = "hello, world";
2. 宽字节字符集 -- 1个字符2byte == 16bit
1>. 存放中文, 拉丁, 棒子, 鬼子
TEXT会根据编码格式的不同自动变化 #define中的##是连接的意思
day02****************************************************
模态对话框:基于对话框(3个类):CAboutDlg 程序名App 程序名Dlg
dialog.cpp中首先完成应用程序类中的InitInstance函数的编写:return TRUE应用程序会继续向下执行;return FALSE应用程序直接退出
所以返回false
注意基于对话框的应用程序 而是在OnInitDialog函数里(窗口框架类是OnCreate)。
OnInitDialog调用时机是:窗口初始化完成且窗口即将显示之前
Qt中却可以在构造中初始化控件:有this指针和setup.....
.rc资源文件中可以脱控件 窗口通过enum里的IDD关联代码
脱控件 右键属性 事件 BNCLICKED addbuttonclicked 或 直接双击 杂项中的id最好改一下
若点击对话框中的一个按钮想弹出另一个新的对话框则必需得:
1. 资源视图中添加对话框资源:.rc右键添加资源 选dialog 新建 脱进去控件 ;
再右键添加类 取名字MyDlg 选基类 完成后会多,出MyDlg的.c和.h文件
2. 给对话框资源关联一个类
3. 使用之前先包含头文件
4. 创建对象
非模态对话框:
秉承了QT中非模态对话框的传统:非模态变量不能是局部变量得最好添加到成员属性中
仍然得添加资源
还得在主窗口的构造函数中creat初始化:m_dlg.Create(IDD_DIALOG1, this);
mfc中的create是初始化的意思
static text上显示一张图片:
只要有事件 先改杂项中的id;因为id是idcstatic的是不能处理消息的
想在程序中操作一个控件必须先关联变量。so 显示图片得先关联变量:右键添加变量:private control类别 起个名字
相应的代码2个地方发生了改变:头文件的类中多了一个属性CStatic m_pic;。还有.cpp的DoDataExchange中多了一个宏函数
*************类通过enum里的IDD关联代码 而控件的关联变量通过多个属性,DoDataExchange中多了一个宏函数
关联后就在OnInitDialog中初始化:
先右键添加资源 导入 .bmp图片
再添加一个CBitmap属性m_bitmap。m_bitmap.LoadBitmapW(IDB_BITMAP1);加载图片
最后m_pic.SetBitmap((HBITMAP)m_bitmap);
密码登陆:
如果想操作编辑框里的内容(往里面设置内容)必须得关联变量,编辑框控件一般绑定value类别,因为框中的东西是字符串......
user设置为张三 密码设为张三疯
因为是value所以变量和数据间交换得手动更新updatedata
可以对一个button进行复杂的关联操作,虽然麻烦但是可以复杂的操作。eg在button上显示一个图
但是不实用所以直接双击就可以添加事件了
下拉框combobox:
Combobox拖进去 右键属性 在行为里的data里直接写南帝北丐....用分号分割 外观Type选项simple/droplist
或右键添加变量 然后初始化中就是增删改查
因为得取编辑框内容 所以也得关联
报表CListCtrl:
CLISTctrl 外观改成report报表模式
依然是关联control类别 在OnInitDialog中:初始化表头、添加数据、属性设置:加网格 整行选中参数是DW类型的宏
(非常象嵌入式中的寄存器设置)
树控件CTreeCtrlDlg:
右键属性 has buttons/line;lines at root;
仍是关联变量 类别是control 在OnInitDialog中 初始化
添加数据 插入节点返回该节点的句柄
显示图片:得添加类比较复杂 秉承了不能是成员变量的特点。
先在.h中添加CImageList属性;资源中添加图片;在create初始化:向属性中添加图片:m_image.Create(32, 32, ILC_COLOR32, 4, 4);
然后......
要求点击小节点会显示其内容:点击小节点的属性、事件selectchange 直接Add进代码。
CTabCtrl即tab页浏览器那个
用封装好的类CTabSheet。class CTabSheet : public CTabCtrl
凭直觉 猜
关联添加变量(添加到的是最初的那个tabsheetdlg.cpp中) control类别 在变量类型上填上CTabSheet 与QT中提升一样
添加2个dialog资源(去掉border 设置style为child) 再关联类(生成.cpp .h文件) 把这两个类包含到.cpp中
用封装好的函数初始化tab页
什么时候添加变量关联? 要操作这个控件 与QT中提升一样
什么时候添加资源关联类? 一个窗口包含有另外的窗口
......
关联类会生成.h .cpp文件 其中.h文件中会有具体的关联:enum { IDD = IDD_DIALOG1 };
在这个类资源上添加各种控件(添加变量关联)
添加变量会在两个地方发生变化 类中会多一个属性 .cpp中DoDataExchange中多了一个宏函数
先打开资源视图看都有什么资源(类) 再看都有什么属性与图对应起来 再看Oinit函数都干了什么
day03**********************************************************
基于单文档类:
messagebox(cstring)用于打印调试
单文档的mfc程序(没有onInitDialog函数) 不使用传统的工具栏 生成4个类
设置图标:时机是初始化之后显示之前 很明显是create函数
mainfrm的OnCreate函数里设置图标,用的是windows的api:HICON hIcon = AfxGetApp()->LoadIconW(IDI_ICON2);
图标是ico格式 添加资源导入记住资源id
setclasslong(this->m_hwnd,)
第一个参数:窗口的资源标示(句柄)m_hwnd
设置窗口大小:
仍是create函数里
Movewindow 或 centerwindow
设置窗口标题:
去文档类(看类视图里有Doc)设置OnNewDocument函数中
SetTitle
登录对话框:
得有对话框资源 添加资源dialog ui界面直接修改标题......
先关联类dialog(生成.cpp .h文件) 再关联dialog窗口中的l inedit变量(多出CString m_user;CString m_pwd;属性 还有双击button控件)
因为得初始化dialog中的控件 但是里面没有OninitDialog 所以得手动添加:
右键属性->消息->重写->OninitDialog 在.cpp中oninitdialog里面:m_user=_T("mike");m_pwd=....
亦或者使用类向导 类向导是个非常吊的东西
登录对话框得先显示所以得在saleSystem.cpp中的SystemApp类中的InitInstance中创建login对象 显示模态对话框(会阻塞)
通过判断模态对话框的返回值INT_PTR nResponse = login.DoModal(); 决定 登录还是退出
回到login.cpp中继续:双击按钮.......
静态拆分窗口:拆的是视图(墙纸) 视图在框架窗口上(墙)
在Mainfrm中 静态拆分窗口 .....怎么设置的???....在框架类Oncreate执行期间被调用OnCreateClient
所以重写给出来的接口OnCreateClient 但是里面没有OnCreateClient 所以得手动添加(同514)
即框架上原来的窗口不用了 用一个拆分的窗口
别忘了屏蔽默认处理
添加两个窗口:
添加类 MFC CTreeView基类 完成(多出来.cpp .h) 同样添加CFormView基类
把这两个窗口类的名字填到上面的静态拆分窗口里
即可显示
左侧树窗口/右侧显示窗口:RUNTIME_CLASS(CSelectView) RUNTIME_CLASS(CDisplayView)
由于不是基于对话框 所以没有Oninitdialog
所以有类似的得右键属性重写OnInitialUpdata 调用时机是视图窗口创建之后 显示之前
1234
点击图标 右侧显示会变:
右键 属性事件 以=开头的都是控件的事件 add进代码里:
switch case不能用于字符串判断 比起if else还是有局限性
如何通知外面已经切换了:则自定义wm消息 仍到消息队列中
消息定义在框架类上 因为5个视图都在框架窗口上
先在mainfrm.h中 自定义消息:#define NM_A (WM_USER+100)
实现自定义消息映射:
1.h中在窗口框架类中声明消息映射即消息处理函数:DECLARE_MESSAGE_MAP()
afx_msg LRESAULT OnMyChange(WPARAM wParam, LPARAM lparam);
2.cpp中 全局区开始消息映射:
BEGIN_MESSAGE_MAP(MyFram, CFrameWnd)
ON_MESSAGE(NM_A,OnMyChange) // 映射入口
END_MESSAGE_MAP()
3.右键....没看清....实现消息函数OnLButtonDown(UINT, CPoint);
由于是自定义消息,需要手动发送自定义消息到消息队列中:PostMessage();写在if else中
但是得用windows的postmessage其第一个参数是框架窗口的句柄,第二个参数是消息NM_A
用windows的postmessage原因是 当前视图里没有nm_a消息
最后实现OnMyChange(WPARAM wParam, LPARAM lparam)
这就是mfc的精髓所在
个人信息的右侧:添加资源dialog id改名为user 去掉border 设置style为child
添加类 基类选cfromview
在Mainfrm中 自定义消息处理函数中:
删除原来的视图第一行第2列
使用m_spliter重新创建一个视图
获取视图对象
初始化视图资源
将刚添加的视图设为活动的视图
刷新窗口拆分类中的布局(显示新创建出来的视图)
菜单操作:重点是怎样给菜单项添加消息
资源视图menu里是菜单资源.......
改id 右键添加事件处理程序 消息类型:commamd 类列表(在哪个窗口处理):cmainframe
会在MainFrm.cpp中的3个位置自动添加一些东西
在展开的函数里postmessage.......
-------------------------------------
无非就是:添加资源(属性中body style id) 关联类(关联id)
主的.cpp中定义应用程序的类行为:
应用程序类中有重写的main入口 app构造 有读配置参数 连接数据库 和关于app
框架类主要 窗口的split
一个非常吊的API函数:CWnd *GetDlgItem(IDC_CHECK_LineEdit);可以操作返回的句柄操作那个lineedit
从资源视图开始找
工具 sqlplus worksheet 执行
commit;
增删改除 不难 量大 熟练度的问题
描述在MFC中如何使用ODBC访问Mysql数据库?
1. 安装Mysql的odbc驱动
2. 使用向导添加数据源
3. 创建MFC单文档/多文档视图应用程序, 添加数据库支持, 选择数据源, 给数据源中的数据库表绑定记录集类
4. 通过绑定的记录集对象访问对应的数据库]