CMake自动生成本地项目,
创建项目
项目保存路径不能有中文
main.cpp
#include "widget.h" //自定义头文件
#include <QApplication> //应用程序头文件
int main(int argc, char *argv[]) //必须是带有参数的main
{
QApplication a(argc, argv); //应用程序对象,有且只有一个
Widget w; //窗口对象
w.show(); //show()显示窗口
ruetrn a.exec(); //应用程序事件循环
}
widget.h
#ifndef WIDGET_H //防止头文件包含
#define WIDGET_H
#include <QWidget>
class Widget : public QWidget
{
Q_OBJECT //要使用信号与槽,属性系统必须得加上这个宏
public:
Widget(QWidget *parent = nullptr);
~Widget();
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent) //调用父类的构造函数,
{
}
Widget::~Widget()
{
}
文件名.pro qmake项目工程
#加载Qt模块
QT += core gui
#如果Qt的版本大于4需要加上widgets
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
#配置C++版本
CONFIG += c++17
#如果不需要使用过时的函数,就启用此宏,如果启用此宏,使用了过时的函数,将发生编译错误
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
#项目所包含的所有源文件、头文件
#源文件
SOURCES += \
main.cpp \
widget.cpp
#头文件
HEADERS += \
widget.h
#文件部署
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
CMake 创建项目
CMakeList.txt
#请求cmake执行的最小版本
cmake_minimum_required(VERSION 3.5)
#指定项目信息 项目名称 项目版本 项目语言
project(Hellocmake VERSION 0.1 LANGUAGES CXX)
#是否包含当前目录 ON表示启用
set(CMAKE_INCLUDE_CURRENT_DIR ON)
#自动uic,moc,rcc
set(CMAKE_AUTOUIC ON) #ui文件的时候,会自动生成源代码
set(CMAKE_AUTOMOC ON) #是否自动元编译,自动生成源代码
set(CMAKE_AUTORCC ON) #是否自动编译资源文件,自动生成源代码
#设置C++的标为17
set(CMAKE_CXX_STANDARD 17)
#强制设置C++标志,如果不支持C++17则会发生错误
set(CMAKE_CXX_STANDARD_REQUIRED ON)
#查找模块
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
#“${QT_VERSION_MAJOR}”查找Qt当前的版本
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)
#项目文件 (项目 资源 UI文件)
set(PROJECT_SOURCES
main.cpp
widget.cpp
widget.h
)
#如果版本号大于等于Qt6 则生成可执行程序(MANUAL_FINALIZATION 必须手动结束生成)
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
qt_add_executable(Hellocmake
MANUAL_FINALIZATION
${PROJECT_SOURCES}
)
# Define target properties for Android with Qt 6 as:
# set_property(TARGET Hellocmake APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
# ${CMAKE_CURRENT_SOURCE_DIR}/android)
# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation
else()
#如果是安卓平台 调用库
if(ANDROID)
add_library(Hellocmake SHARED
${PROJECT_SOURCES}
)
# Define properties for Android with Qt 5 after find_package() calls as:
# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
else()
add_executable(Hellocmake
${PROJECT_SOURCES}
)
endif()
endif()
#给目标连接库:
target_link_libraries(Hellocmake PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
#设置目标的属性
set_target_properties(Hellocmake PROPERTIES
MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
MACOSX_BUNDLE TRUE
WIN32_EXECUTABLE TRUE
)
install(TARGETS Hellocmake
BUNDLE DESTINATION .
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
#终止生成
if(QT_VERSION_MAJOR EQUAL 6)
qt_finalize_executable(Hellocmake)
endif()
添加类
CMakeList.txt里面需要手动添加要添加的类
#项目文件 (项目 资源 UI文件)
set(PROJECT_SOURCES
main.cpp
widget.cpp
widget.h
hello.cpp
hello.h
)
在VC上创建Qt项目
CMakeList.txt
cmake_minimum_required (VERSION 3.8)
project (Qtpro)
#指定C++标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
#指定头文件包含目录
include_directories("D:\\QT\\6.2.4\\msvc2019_64\\include")
#查找模块
find_package(Qt6 COMPONENTS Widgets)
#指定目标生成位置
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/bin)
#增加可执行文件
add_executable (Qtpro "main.cpp")
#给目标连接库:
target_link_libraries(Qtpro Qt6::Widgets)
main.cpp
#include<QApplication>
#include<QWidget>
int main(int argc,char *argv[])
{
QApplication a(argc, argv);
QWidget w;
w.show();
return 0;
}
在CMakeList.txt中添加宏
add_compile_definitions(QT_ON_DEBUG_OUTPUT)
#include<QApplication>
#include<QDebug>
#include<QDateTime>
#include<QElapsedTimer>
void testQByteArray();
void testQString();
void testQByteArrayAndQString();
void testQVariant();
void testQPoint();
void testLine();
void testQSize();
void testQRect();
void testDate();
void testTime();
void testQDateTime();
class My
{
public:
QString name;
int age;
My() = default;
My(const char* name) :name(name)
{
age = 18;
}
//重置输出函数
friend QDebug operator<<(QDebug out, const My& m)
{
out << m.name << m.age;
return out;
}
};
//Qt6以前需要手动注册自定义类才能使用,Qt6可以自动识别
//Q_DECLARE_METATYPE(My)
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
testQDateTime();
return a.exec();
}
void testType()
{
qint16 age = 12222;
qint64 tel = 1222222222;
qDebug("age:%d", age);
qInfo("qInfo");
qWarning("qWarning");
qCritical("qCritical");
//qFatal("qFatal");//只能用C风格写
qDebug() << "tel:" << tel;//会自动插入空格
//不能取消换行
//取消数据之间的空格
qDebug().nospace() << "tel:" << tel;
//取消双引号
qDebug().noquote() << QString("hello world");
}
void testQByteArray()
{
//定义一个字符数组
QByteArray name = "hello";
qInfo() << name;
//在尾部追加数据
name.append(" is ");
//在头部添加数据
name.push_front("i am");
name.prepend("hello");
//指定位置插入
name.insert(5, " hi ");
qInfo() << name;
//删除
name.remove(6, 4);
//从尾部截断
name.chop(1);
//丢掉指定位置后面的所有字符
name.truncate(name.indexOf("a"));
//清空所有
name.clear();
qInfo() << name;
name = "i hello world";
qInfo() << name;
//判断字符中是否包含某个字符串
if (name.contains("world"))
{
qInfo() << "包含 world";
}
//判断字符是否以I开始,以什么结束
if (name.startsWith("i"))
{
qInfo() << "以i开始";
}
//查找字符串
qsizetype pos = name.indexOf('h');
qInfo()<<pos;
pos = name.lastIndexOf('h');
qInfo() << pos;
//迭代器
for (auto& c : name)
{
qInfo() << c;
}
//字节数组和其他数据类型转换
//int --->QByteArray
QByteArray num;
num.setNum(1314520, 16);
qInfo() << num;
num.setNum(3.1415, 'g', 2);
qInfo() << num;
qInfo() << QByteArray::number(520);
QByteArray sum("666666");
//qInfo() << sum.toHex();
qInfo() << sum.toInt() << sum.toLongLong() << sum.toShort();
bool ok;
sum.toUInt(&ok, 16);
}
void testQString()
{
QString name("hello");
qInfo() << name;
name.replace("h", "g", Qt::CaseSensitivity::CaseInsensitive/*忽略大小写*/);
qInfo() << name;
QString _name = "hhh";
qint32 age = 122;
QString job = "吃饭";
qInfo() << _name + QString::number(age) + job;
//C风格
qInfo() << QString::asprintf("我是%s,今年%d,喜欢%s", _name.toStdString().data(), age, job.toStdString().data());
//Qt 风格
qInfo() << QString("我是%1,今年%2,喜欢%3").arg(_name).arg(age).arg(job);
//输出时间
quint32 second = 3600000;
qInfo()<<QString("%1天,%2:%3:%4").
arg(second / 60 / 60 / 24).
arg(second%24).
arg(second %24%60,2/*填充几个*/, 10/*填充格式*/, QChar('0')).
arg(second%24%60%60);
QString s("你好");
//获取本地编码 gdk
qInfo() << s.toLocal8Bit();
//获取utf8
qInfo() << s.toUtf8();
}
void testQByteArrayAndQString()
{
QByteArray array("hello你好");
qInfo() << array.size();//字节个数
QString string("hello你好");
qInfo() << string.size();//字符个数
}
void testQVariant()
{
//QVariant 变体类型,可以存储大量的不同类型数据
QVariant var(520);
qInfo() << var;
//获取值
qInfo() << var.value<int>();
qInfo() << var.toInt() << var.toLongLong();
//重新设置值
var.setValue("Hello");//const char *类型
//var.setValue(QString("Hello"));//QString 类型
qInfo() << var;
auto v = QVariant::fromValue(QString("Hello"));//返回QVariant类型
qInfo() << var.metaType().id()<<var.userType();//返回当前类型
qInfo() << var.typeName();
//判断能否转换到指定类型
if (var.canConvert<QString>())
{
qInfo() << var.value<QString>();
}
//自定义类型必须通过setValue来设置
My m("Hello world");
QVariant q;
q.setValue(m);
qInfo() << q;
//获取值
qInfo() << q.value<My>();
}
void testQPoint()
{
QPoint point(2, 3);
qInfo() << point << point.x() << point.y();
//修改数据
point.rx() = 4;
point.ry() = 5;
qInfo() << point;
point.setX(6);
point.setY(7);
qInfo() << point;
//曼哈顿距离
qInfo() << point.manhattanLength();
//求两点之间的距离
QPoint p1(3, 3);
QPoint p2(6, 6);
qInfo() << QPoint(p1 - p2).manhattanLength();
//坐标交换
qInfo() << QPoint(2, 7).transposed();
}
void testLine()
{
QLine line(0, 0, 2, 2);
qInfo() << line;
qInfo() << line.dx() << line.dy();
//移动
line.translate(3, 3);
//返回临时的,没有改变原来的位置
qInfo()<<line.translated(3, 3);
qInfo() << line;
}
void testQSize()
{
QSize size(640, 480);
qInfo() << size;
//返回交换的值
qInfo() << size.transposed();
//把两个宽度高度最小的拿出来,构造一个新size
QSize s1(33, 44);
QSize s2(44, 33);
qInfo() << s1.boundedTo(s2);
//把两个宽度高度最大的拿出来,构造一个size
qInfo() << s1.expandedTo(s2);
//缩放
qInfo() << QSize(55, 55).scaled(10, 10, Qt::AspectRatioMode::IgnoreAspectRatio);
}
void testQRect()
{
QRect rect(0, 0, 6, 6);
//获取属性
qInfo() << rect.x() << rect.y() << rect.width() << rect.height();
//设置属性
rect.setRect(1, 1, 2, 2);
rect.setX(0);
rect.setY(0);
//其他获取属性
qInfo() << rect.topLeft() << rect.topRight() << rect.bottomLeft() << rect.bottomRight();
//移动矩形
QRect r(0, 0, 5, 5);
r.moveTo(1, 2);
qInfo() << r;
//调整矩形大小
qInfo() << QRect(0, 0, 33, 33).adjusted(5, 5, -5, -5);
//浮点型
qInfo() << QRect(1.1, 2.2, 3.3, 4.4);
}
void testDate()
{
//日期对象
QDate date(2023, 10, 1);
qInfo() << date;
//获取年月日
qInfo() << date.year() << date.month() << date.day();
//添加日期
date = date.addDays(30);
qInfo() << date;
//把日期格式转换为字符串
qInfo() << date.toString(Qt::DateFormat::ISODate);
qInfo() << date.toString("yyyy/MM/dddd");
//获取系统的当前日期
auto curdate = QDate::currentDate();
qInfo() << curdate;
}
void testTime()
{
QTime time(5, 2, 1);
qInfo() << time;
//获取属性
qInfo() << time.hour() << time.minute() << time.second() << time.msec();
//让时间增加
time = time.addSecs(2);
time = time.addMSecs(60);
//把时间格式转换成想要的字符串
qInfo() << time.toString("hh点mm分ss秒 zzz");
qInfo() << time.toString("AP hh点mm分ss秒 zzz");
//获取当前时间
qInfo() << QTime::currentTime();
//从指定字符串获取时间
qInfo() << QTime::fromString("02:22:20");
}
void testQDateTime()
{
//日期时间
QDateTime dt = QDateTime::currentDateTime();
qInfo() << dt;
//获取日期时间
auto date = dt.date();
auto time = dt.time();
//格式化成字符串
qInfo() << dt.toString("yyyy/MM/dd,hh:mm:ss AP");
//计算过去计时器
QElapsedTimer etimer;
etimer.start();
for (int i = 0; i < 100000000; i++)
{
}
qInfo() << etimer.elapsed();
//重新计时
etimer.restart();
for (int i = 0; i < 100000000; i++)
{
}
qInfo() << etimer.elapsed();
}
Qt容器类
Qt提供了以下顺序容器:QList、QStack和QQueue。 对于大多数应用程序,QList是最好的类型。 它提供了非常快的追加。 如果您确实需要一个链表,请使用std::list。 QStack和QQueue是提供LIFO和FIFO语义的方便类。
Qt还提供了这些关联容器:QMap、QMultiMap、QHash、QMultiHash和QSet。 “Multi”容器方便地支持与单个键关联的多个值。 “哈希”容器通过使用哈希函数而不是对排序集进行二进制搜索来提供更快的查找。
作为特殊情况,QCache和QContiguousCache类在有限的缓存存储中提供对象的高效哈希查找。
#include<QApplication>
#include<QDebug>
#include<QDateTime>
#include<QElapsedTimer>
#include<QStack>
#include<QQueue>
void testQByteArray();
void testQString();
void testQByteArrayAndQString();
void testQVariant();
void testQPoint();
void testLine();
void testQSize();
void testQRect();
void testDate();
void testTime();
void testQDateTime();
void testIterator();
void testQList();
void testQStackandQQueue();
void testQStringList();
void testQMap();
void testQHash();
void testSelClass();
//Qt6以前需要手动注册自定义类才能使用,Qt6可以自动识别
//Q_DECLARE_METATYPE(My)
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
testSelClass();
return a.exec();
}
void testIterator()
{
QList<int> list = { 1,2,3,4 };
//java风格迭代器
QListIterator javeit(list);
while (javeit.hasNext())
{
qInfo() << javeit.next();
}
//STL风格
for (auto& i : list)
{
qInfo() << i;
}
for (QList<int>::iterator it = list.begin(); it != list.end(); it++)
{
qInfo() << *it;
}
}
void testQList()
{
QList<QString> name = { "hello" };
//添加尾部
name << "world";
name.push_back("hi");
name.append("i");
//前部
name.prepend("an");
qInfo() << name;
//删除
name.remove(1, 2);
name.removeAt(0);
name.removeAll("hello");
//查找
qInfo() << name.indexOf("Hello");
//把元素拿出来(删除)
qInfo() << name.takeAt(0);
for (int i = 0; i < name.size(); i++)
{
qInfo() << name[i];
}
}
void testQStackandQQueue()
{
QStack<int> sk;
sk.push(1);
sk.push(2);
sk.push(3);
while (!sk.isEmpty())
{
qInfo() << sk.top();
sk.pop();
}
QQueue<int> qu;
qu.enqueue(3);
qu.enqueue(2);
qu.enqueue(1);
while (!qu.isEmpty())
{
qInfo() << qu.front();
qu.dequeue();
}
}
void testQStringList()
{
QStringList name = { "Hello" };
//添加数据
name << "world"<<"hello";
name.push_back("i");
name.append("am");
//判断是否包含某一个字符串
qInfo() << name.contains("Hello",Qt::CaseSensitivity::CaseInsensitive);
//过滤满足条件的字符串
qInfo() << name.filter("hello");
//把所有的字符串连接为一个字符串
qInfo() << name.join(" ");
//删除重复元素
qInfo() << name.removeDuplicates();
//排序
name.sort();
qInfo() << name;
//分割
QString str("hello hi ii am world");
auto list = str.split(" ");
qInfo() << list;
}
void testQMap()
{
QMap<QString, QString> map;
map.insert("i", "我");
map.insert("me", "我");
map["you"] = "你";
//获取
qInfo() << map["Hello"] << map.value("wlord", "世界");
//获取所有的key
qInfo()<<map.key("我");
//获取所有key
qInfo() << map.keys();
//获取所有的值
qInfo() << map.values();
qInfo() << map;
//遍历 得到的是值
for (auto& var : map)
{
qInfo() << var;
}
//遍历 得到的是键
auto key=map.keys();
for (auto& var : key)
{
qInfo() << var;
}
}
void testQHash()
{
QHash<int, QString> hash;
hash.insert(1, "hh");
hash.insert(2, "你好");
hash.insert(3, "模态");
//获取数据
qInfo() << hash.value(2, "hhhh");
qInfo() << hash;
}
class MM
{
public:
int age;
QString name;
//使用QMap存储自定义类型,必须要有拷贝构造
//如果QMap自定义作为键必须比较
bool operator<(const MM& m)
{
return this->age < m.age;
}
//如果QHash自定义作为键必须比较
bool operator==(const MM& m)
{
return this->age == m.age;
}
MM(int age,const QString &name):age(age),name(name){}
friend QDebug operator<<(QDebug out, const MM& m)
{
out << m.age << m.name;
return out;
}
friend size_t qHash(const MM&& m);
};
size_t qHash(const MM&& m)
{
return m.age;
}
void testSelClass()
{
//自定义的类作为值
QMap<int, MM> map;
for (int i = 0; i < 5; i++)
{
map.insert(i, MM(i, QString("Hello_%1").arg(i)));
}
qInfo() << map;
//自定义的类作为键
QMap<MM,int> map;
for (int i = 0; i < 5; i++)
{
map.insert(i, MM(i, QString("Hello_%1").arg(i)));
}
qInfo() << map;
//hash 对于自定义的类做键,必须有QHash函数
QHash<MM, int> hash;
for (int i = 0; i < 5; i++)
{
hash.insert(MM(i, QString("Hello_%1").arg(i)),i+1);
}
}
#include<QApplication>
#include<QWidget> //窗口
#include<QPushButton>
class widget:public QWidget
{
//元对象系统、信号与槽
Q_OBJECT
public:
widget(QWidget* parent = nullptr)
{
auto btn = new QPushButton("关闭窗口", this);
//绑定信号与槽
//信号发送者:btn
//发送什么信号:clicked
// 信号接受者this
// 槽函数:&widget::close
//QObject::connect(btn, &QPushButton::clicked, this, &widget::close);
auto con=connect(btn, &QPushButton::pressed, this, &QPushButton::close);
//断开信号和槽的连接
//disconnect(btn, &QPushButton::pressed, this, &QPushButton::close);
disconnect(con);
}
void Button()
{
//按钮 通过new
auto btn = new QPushButton;
auto btn2 = new QPushButton("Hello", this);
//显示按钮
btn->show();
//显示在主窗口上面
btn->setParent(this);
//给按键设置文本
btn->setText("Button");
//移动按钮
btn->move(btn2->x() + btn2->width(), 0);
//调整大小
btn->resize(100, 30);
}
};
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
widget w;
w.show();
return a.exec();
}
//显示告诉moc这个源文件需要元编译 (把类的声明和定义放在一个文件时需要定义
#include "main.moc"
在CMAKEList.txt中添加
#自动moc
set(CMAKE_AUTOMOC ON)
widget.h
#pragma once
#include<QWidget> //窗口
class Widget :public QWidget
{
Q_OBJECT
public:
Widget(QWidget* parent = nullptr);
//槽函数 一般写在public slots:下
public slots:
//响应按钮pressed信号
void OnButtonPressed();
public:
static void OnButtonRelease();
};
widget.cpp
#include"widget.h"
#include<QPushButton>
#include<QDebug>
void GlobalButton();
Widget::Widget(QWidget* parent)
:QWidget(parent)
{
//自定义的槽函数
//1.槽函数返回类型为void
//2槽函数的参数不能多于信号的参数
auto btn = new QPushButton("Hello", this);
//关联信号与槽 会导致无限循环
//connect(btn, &QPushButton::clicked, btn, &QPushButton::click);
//关联成员函数
connect(btn, &QPushButton::clicked, this, &Widget::OnButtonPressed);
//关联静态函数
connect(btn, &QPushButton::clicked, this, &Widget::OnButtonRelease);
//关联全局函数
connect(btn, &QPushButton::clicked, this, GlobalButton);
//关联lambda表达式 =按值捕获
int cnt = 0; //栈区的临时变量 构造函数结束,会自动释放
//引用捕获会释放
connect(btn, &QPushButton::clicked, this, [=,&cnt] ()
{
qInfo() << __FUNCTION__<<cnt++;
btn->setText("Hello world");
});
//lambda注意事项
}
//响应按钮pressed信号
void Widget::OnButtonPressed()
{
qInfo() << __FUNCTION__;
}
void Widget::OnButtonRelease()
{
qInfo() << __FUNCTION__;
}
void GlobalButton()
{
qInfo() << __FUNCTION__;
}
自定义信号
SubWidget
.h
#ifndef _SUBWIDGET_H_
#define _SUBWIDGET_H_
#include<QWidget>
class SubWidget : public QWidget
{
Q_OBJECT
public:
SubWidget(QWidget* parent = nullptr);
//自定义信号
//1,返回类型必须是void
//2,参数必须等于(或多于)槽函数的参数
//3,信号只有函数的声明,不需要自己定义
//4,信号必须定义在signals下面
//5,发送信号使用emit宏
signals:
void cutMainWindow();
void cutMainWindow(int);
void cutMainWindow1(const QString&);
};
#endif
.cpp
#include"SubWidget.h"
#include<QPushButton>
SubWidget::SubWidget(QWidget* parent)
:QWidget(parent)
{
resize(640, 480);
setWindowTitle("子窗口");
auto btn = new QPushButton("切换到主窗口", this);
//信号可以关联信号
//connect(btn, &QPushButton::clicked, this, &SubWidget::cutMainWindow);
connect(btn, &QPushButton::clicked, this, [=]()
{
emit this->cutMainWindow();
emit this->cutMainWindow1("我还想再显示会儿");
emit cutMainWindow(1314520);
});
}
Widget
.h
#ifndef _WIDGET_H_
#define _WIDGET_H_
#include<QWidget>
class SubWidget;
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget* parent = nullptr);
public slots:
void onCutMainWindow();
void onCutMainWindow(int);
private:
SubWidget* subWidget = nullptr;
};
#endif
.cpp
#include"Widget.h"
#include<QPushButton>
#include"SubWidget.h"
#include<QDebug>
Widget::Widget(QWidget* parent)
:QWidget(parent)
,subWidget(new SubWidget)
{
//subWidget->show();
resize(640, 480);
setWindowTitle("主窗口");
auto btn = new QPushButton("切换到子窗口", this);
connect(btn, &QPushButton::clicked, subWidget,&QWidget::show);
connect(btn, &QPushButton::clicked, this, &QWidget::hide);
//切换到主窗口
//cutMainWindow有重载,connect不知道你要关联哪个信号,二义性问题
//connect(subWidget, &SubWidget::cutMainWindow, this, &Widget::onCutMainWindow);
//1,通过函数指针解决
void (SubWidget:: *cutOne)() = &SubWidget::cutMainWindow; //void SubWidget::cutMainWindow();
void (SubWidget:: * cutTwo)(int) = &SubWidget::cutMainWindow; //void SubWidget::cutMainWindow(int);
//connect(subWidget, cutOne, this, &Widget::onCutMainWindow);
//connect(subWidget, cutTwo, this, &Widget::onCutMainWindow);
//2,通过QOverload类解决 推荐使用这一种
//connect(subWidget,QOverload<>::of(& SubWidget::cutMainWindow), this,QOverload<>::of(& Widget::onCutMainWindow));
connect(subWidget, QOverload<int>::of(&SubWidget::cutMainWindow), this, QOverload<int>::of( & Widget::onCutMainWindow));
//3,可以使用Qt4的方式解决 通过宏进行转换
//不安全,因为是使用宏来转换的,会把函数转换成字符串,不会进行安全检查
//函数名写错了也不会报错,只有再运行的时候,才会给你提示 SLOT放在pubic slots下面
connect(subWidget,SIGNAL(cutMainWindow()), this, SLOT(onCutMainWindow()));
connect(subWidget, SIGNAL(cutMainWindow(int)), this, SLOT(onCutMainWindow(int)));
//connect(subWidget, &SubWidget::cutMainWindow1, this, [=](const QString& str)
// {
// qInfo() << str;
// subWidget->hide(); //子窗口隐藏
// this->show(); //主窗口显示
// });
}
void Widget::onCutMainWindow()
{
subWidget->hide(); //子窗口隐藏
this->show(); //主窗口显示
}
void Widget::onCutMainWindow(int val)
{
onCutMainWindow();
qInfo() << val;
}
内存管理、智能指针
#include<QApplication>
#include<QWidget>
#include<QDebug>
#include<QPushButton>
#include<QPointer>
class Button : public QPushButton
{
Q_OBJECT
public:
using QPushButton::QPushButton;
Button(QWidget* parnet = nullptr)
:QPushButton(parnet)
{
}
~Button()
{
qInfo() << __FUNCTION__;
}
};
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget* parent = nullptr)
:QWidget(parent)
{
resize(640, 480);
//testQPointer();
//testCPP();
//test1();
}
void testQPointer()
{
//QObject对象的专享指针
//超出作用域不会自动释放对象的内存
QPointer<Button> button = new Button(this);
button->setText("hello world");
//...
//delete button;
if (button)
{
qInfo() << button->text()<<button;
}
else
{
qInfo() <<"button is nullptr" << button;
}
//如果存储的不是QObject的对象 报错:error C2661: “QWeakPointer<QObject>::QWeakPointer”: 没有重载函数接受 2 个参数
//QPointer<int> i = new int(66);
}
void testCPP()
{
//指针超出作用域会自动释放对象
QScopedPointer<Button> btn(new Button(this));
button.reset(new Button("button", this));
//共享指针
QSharedPointer<int> pint(new int(66));
qInfo() << *pint;
pint.reset();
//监视指针
QWeakPointer<int> wptr(pint);
//判断共享指针还能不能使用
if (wptr)
{
qInfo() << "wptr is not nullptr";
//可以获得共享指针
auto ptr = wptr.toStrongRef();
qInfo() << "wptr " << *ptr;
}
else
{
qInfo() << "wptr is nullptr";
}
QScopedArrayPointer<Button> ages(new Button[10]);
}
void test1()
{
//如果没有手动的delete,或者指定父对象,那么就会发生内存泄漏
//auto btn = new Button;
btn = new Button("delete");
btn->show();
connect(btn, &QPushButton::clicked, this, [=]()
{
delete btn; //调用立马释放内存
//btn->deleteLater(); //调用之后,要等到下一次事件循环的时候,才会释放(安全)
qInfo() << "你touch me";
});
//当对象释放之后,会触发一个信号,destroyed
connect(btn, &QPushButton::destroyed, this, [](QObject* obj)
{
qInfo() << "btn destroyed"<<static_cast<Button*>(obj)->text();
});
//只要你指定了父对象,则父对象释放的时候,子对象会自动的释放
auto btn1 = new Button(this);
btn1->move(100, 0);
}
~Widget()
{
qInfo() << __FUNCTION__;
//delete btn; //常规释放
//btn->deleteLater(); //使用QObject提供的专门释放的函数(稍后释放)
}
private:
Button* btn;
QScopedPointer<Button> button;
};
//隐式共享类
class EmpData : public QSharedData
{
public:
int age;
QString name;
};
class Emp
{
public:
Emp(int age,const QString& name)
:d(new EmpData)
{
d->age = age;
d->name = name;
};
void setAge(int age)
{
d->age = age;
}
void setName(const QString& name)
{
d->name = name;
}
friend QDebug operator<<(QDebug out, const Emp& other)
{
out << other.d->age << other.d->name;
out << &other.d->age << &other.d->name;
return out;
}
//private:
//隐式共享指针 修改数据的时候,自动复制一份
//QSharedDataPointer<EmpData> d;
//显示共享指针 需要的时候必须自己调用函数复制一份
QExplicitlySharedDataPointer<EmpData> d;
};
int main(int argc,char* argv[])
{
QApplication a(argc, argv);
Emp emp(20, "摸鱼");
Emp maye = emp;
qInfo() << emp << maye;
//写时拷贝
maye.d.detach();
maye.setName("maye");
qInfo() << emp << maye;
Widget w;
w.show();
return a.exec();
}
#include "main.moc"
访问属性,自定义属性
#include<QApplication>
#include<QDebug>
#include<QProperty>
class Student : public QObject
{
Q_OBJECT
//通过属性操控成员变量
Q_PROPERTY(int age READ getAge WRITE setAge RESET resetAge NOTIFY ageChanged)
public:
Student(QObject* parent = nullptr)
:QObject(parent)
{
}
//获取属性值的函数:Read访问器
int getAge()const
{
return m_age;
}
//设置属性值的函数:write
void setAge(int age)
{
this->m_age = age;
if (m_age != age)
{
//信号必须手动发送
emit ageChanged(age);
}
}
//重置属性值的函数 reset
void resetAge()
{
if (m_age != 18)
{
m_age = 18;
emit ageChanged(m_age);
}
}
signals:
void ageChanged(int age);
private:
int m_age;
};
class Student1 : public QObject
{
Q_OBJECT
//让age属性直接和成员变量m_age建立关联
//这样的话,当属性改变的时候,会自动的触发信号
Q_PROPERTY(int age MEMBER m_age NOTIFY ageChanged)
public:
Student1(QObject* parent = nullptr)
:QObject(parent)
{
}
void showAge()
{
qInfo() << "m_age" << m_age;
}
void setAge(int age)
{
setProperty("age", age);
}
signals:
void ageChanged(int age);
private:
int m_age;
};
void testPerpoty()
{
QObject obj;
//通过函数获取对象名
obj.setObjectName("obj");
qInfo() << obj.objectName();
//通过属性获取/修改对象名
obj.setProperty("objectName", "object");
qInfo() << obj.property("objectName");
//如果不是代码提供的属性,这个就是临时的属性
obj.setProperty("maye", "顽石");
qInfo() << obj.property("maye");
//取消临时属性
obj.setProperty("maye", QVariant());
qInfo() << obj.property("maye");
}
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
Student1 maye;
QObject::connect(&maye, &Student1::ageChanged, [=](int age)
{
qInfo() << "slot age " << age;
});
//property实际上是通过函数获取属性值的
maye.setProperty("age", 20);
qInfo() << maye.property("age");
maye.setProperty("age", QVariant());
maye.setProperty("age", QVariant());
maye.setProperty("age", QVariant());
maye.showAge();
qInfo() << "-----------";
maye.setAge(666);
return a.exec();
}
绑定属性
#include<QApplication>
#include<QDebug>
#include<QObjectBindableProperty>
//定义一个矩形
struct Rectangle
{
QProperty<int> w;
QProperty<int> h;
QProperty<int> area;
Rectangle(int w, int h)
:w(w),h(h)
{
//area = w * h;
//area的求值规则
area.setBinding([=]() {return this->w * this->h; });
}
};
//定义三角形
struct Triangle :public QObject
{
Q_OBJECT
//qreal bottomLen; //底边长
//qreal height; //高
//qreal area;
public:
Triangle()
{
area.setBinding([=]() {return bottomLen * height / 2; });
}
Triangle(qreal len , qreal h )
:bottomLen(len),height(h)
{
//area = bottomLen * height / 2;
area.setBinding([=]() {return bottomLen * height / 2; });
}
signals:
void bottomLenChanged(qreal area);
void heightChanged(qreal area);
void areaChanged(qreal area);
public:
//类名 类型 变量 初始值 关联信号
Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(Triangle, qreal, bottomLen,3,&Triangle::bottomLenChanged)
Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(Triangle, qreal, height,3, &Triangle::heightChanged)
Q_OBJECT_BINDABLE_PROPERTY(Triangle, qreal, area, &Triangle::areaChanged)
};
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
Rectangle r(3, 6);
qInfo() << r.w << r.h << r.area; //18
r.w = 20;
r.h = 7;
qInfo() << r.w << r.h << r.area; //120 实际上是18
Triangle t;
QObject::connect(&t, &Triangle::areaChanged, [](qreal area)
{
qInfo() << "areaChanged"<<area;
});
qInfo() << t.bottomLen << t.height << t.area;
t.height = 10;
qInfo() << t.bottomLen << t.height << t.area;
return a.exec();
}
#include "main.moc"
实时类型信息
#include<QApplication>
#include<QDebug>
#include<QMetaClassInfo>
class Button :public QPushButton
{
Q_OBJECT
Q_CLASSINFO("version","Button 1.0")
Q_CLASSINFO("author", "顽石老师")
public:
Button(QWidget* parent = nullptr)
:QPushButton(parent)
{
}
};
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
QScopedPointer<Button> btn(new Button);
//判断btn继承自哪个类
if (btn->inherits("QWidget"))
{
qInfo() << "inherits QWidget";
}
//获取更多的类型信息
auto meta = btn->metaObject();
qInfo()<< meta->className();
auto cnt = meta->classInfoCount();
for (int i = 0; i < cnt; i++)
{
qInfo() << meta->classInfo(i).name()<<meta->classInfo(i).value();
}
return a.exec();
}
大小位置设置
#include<QApplication>
#include<QWidget>
#include<qdebug.h>
int main(int argc,char* argv[])
{
QApplication a(argc, argv);
//创建一个窗口
QWidget w;
w.show();
//窗口的大小和位置
qInfo() << w.x() << w.y() << w.pos(); //包括边框
qInfo() << w.width() << w.height() << w.size(); //不包括边框
//获取窗口的几何大小
qInfo() << w.geometry() //不包括边框
<< w.frameGeometry(); //包括边框
qInfo() << w.rect(); //窗口的内部矩形大小 QRect(0,0,width(),height())
//移动窗口的位置
w.move(0, 0);
//调整窗口大小 带边框
w.resize(250, 250);
//设置几何 不带边框
w.setGeometry(0, 0, 250, 250);
//设置固定的大小
w.setFixedSize(640, 480);
//设置固定大小之后,不能调整窗口大小
w.resize(250, 250);
//设置窗口的最大、最小大小
w.setMaximumSize(640, 480);
w.setMinimumSize(250, 250);
qInfo() << w.maximumSize() << w.minimumSize();
return a.exec();
}
坐标系的转换
#include<QApplication>
#include<QWidget>
#include<qdebug.h>
int main(int argc,char* argv[])
{
QApplication a(argc, argv);
//坐标系统转换
QWidget w;
w.resize(640, 480);
//控件
auto w1 = new QWidget(&w);
auto w2 = new QWidget(w1);
auto w3 = new QWidget(&w);
w1->setGeometry(100, 100, 100, 100);
w1->setStyleSheet("background-color:blue");
w2->setGeometry(20, 20, 20, 20);
w2->setStyleSheet("background-color:brown");
//必须把所有的子控件初始化完毕之后再show
w.show();
qInfo() << w1->pos();
//w1的50,50位置,在父控件上的坐标是多少 (150,150)
qInfo() << w1->mapToParent(QPoint(50, 50));
//w1的父控件上的120,120坐标,在w1上是多少 (20,20)
qInfo() << w1->mapFromParent(QPoint(120, 120));
//w2的0,0坐标,再爷爷w上的位置是多少 (120,120)
qInfo() << w2->mapTo(&w, QPoint(0, 0));
qInfo() << w2->mapFrom(&w, QPoint(100, 100));
//相对于全局的坐标 741 385
qInfo() << w.mapFromGlobal(QPoint(741, 385));
qInfo() << w.mapToGlobal(QPoint(0, 0));
return a.exec();
}
内容边距
#include<QApplication>
#include<QWidget>
#include<qdebug.h>
int main(int argc,char* argv[])
{
QApplication a(argc, argv);
//坐标系统转换
QWidget w;
w.resize(640, 480);
//控件
auto w1 = new QWidget(&w);
auto w2 = new QWidget(w1);
auto w3 = new QWidget(&w);
w1->setGeometry(100, 100, 100, 100);
w1->setStyleSheet("background-color:blue");
w2->setGeometry(20, 20, 20, 20);
w2->setStyleSheet("background-color:brown");
//必须把所有的子控件初始化完毕之后再show
w.show();
qInfo() << w1->pos();
//w1的50,50位置,在父控件上的坐标是多少 (150,150)
qInfo() << w1->mapToParent(QPoint(50, 50));
//w1的父控件上的120,120坐标,在w1上是多少 (20,20)
qInfo() << w1->mapFromParent(QPoint(120, 120));
//w2的0,0坐标,再爷爷w上的位置是多少 (120,120)
qInfo() << w2->mapTo(&w, QPoint(0, 0));
qInfo() << w2->mapFrom(&w, QPoint(100, 100));
//相对于全局的坐标 741 385
qInfo() << w.mapFromGlobal(QPoint(741, 385));
qInfo() << w.mapToGlobal(QPoint(0, 0));
return a.exec();
}
光标样式
#include<QApplication>
#include<QWidget>
#include<QDebug>
int main(int argc,char* argv[])
{
QApplication a(argc, argv);
QWidget w;
w.setCursor(QCursor(Qt::OpenHandCursor));
auto btn = new QPushButton("切换光标形状", &w);
QObject::connect(btn, &QPushButton::clicked, [&]()
{
static int i = 0;
w.setCursor(QCursor(Qt::CursorShape(i)));
i = (i + 1) % 22;
});
//自定义光标
w.setCursor(QCursor(QPixmap("maye.png"), 0, 0));
w.show();
qInfo()<< QCursor::pos();//得到鼠标的全局位置
QCursor::setPos(0, 0);//该变鼠标位置
return a.exec();
}
设置窗口图标、标题、状态、标志
#include<QApplication>
#include<QWidget>
#include<QIcon>
#include<QPushButton>
void testWindowIcon()
{
auto w = new QWidget;
w->setWindowIcon(QIcon("maye.png"));
QIcon icon = w->windowIcon();
qInfo() << icon;
w->show();
auto w1 = new QWidget;
w1->show();
}
void testWindowTitle()
{
auto w = new QWidget;
w->setWindowTitle("社会你顽哥,人狠话不多[*]");
QApplication::setApplicationDisplayName("Widget");
qInfo() << w->windowTitle();
//窗口是否被修改了
w->setWindowModified(true);
auto btn = new QPushButton("保存", w);
QObject::connect(btn, &QPushButton::clicked, [=]()
{
w->setWindowModified(false);
qInfo() << w->isWindowModified();
});
//设置窗口的不透明度
//w->setWindowOpacity(0); //只对窗口生效
//btn->setWindowOpacity(0.2); //对控件没用
w->show();
}
void testWindowState()
{
auto w = new QWidget;
//获取窗口状态
qInfo() << w->windowState();
//设置窗口的状态
//w->setWindowState(Qt::WindowState::WindowMinimized);
//点击按钮能够在最小化和正常显示之间切换
auto btn = new QPushButton("button");
btn->show();
QObject::connect(btn, &QPushButton::clicked, [=]()
{
qInfo() << w->windowState();
//通过位运算^(按位异或)如果有这个state就去掉,如果没有就加上
//w->setWindowState(w->windowState() ^ Qt::WindowMinimized);
w->setWindowState((w->windowState() & ~Qt::WindowState::WindowMinimized) | Qt::WindowActive);
qInfo() << w->windowState();
});
qInfo() << w->windowState();
w->show();
//设置窗口显示状态
w->showFullScreen();
w->showMaximized();
w->showMinimized();
w->showNormal();
}
void testWindowFlag()
{
auto w = new QWidget;
auto btn = new QPushButton("button", w);
w->resize(640, 480);
//设置窗口标志
btn->setWindowFlag(Qt::WindowType::ToolTip);
btn->show();
w->setWindowFlags(w->windowFlags() | Qt::WindowType::FramelessWindowHint);
w->show();
//获取窗口的标志
qInfo() << w->windowFlags();
qInfo() << btn->windowFlags();
//判断是不是顶层窗口
qInfo() << w->isTopLevel()<<btn->isTopLevel();
}
int main(int argc,char* argv[])
{
QApplication a(argc, argv);
//testWindowIcon();
//testWindowTitle();
//testWindowState();
testWindowFlag();
return a.exec();
}
父子关系
#include <QApplication>
#include<QWidget>
#include<QLabel>
#include<QDebug>
class Widget:public QWidget
{
Q_OBJECT
public:
Widget(QWidget*parent=nullptr)
:QWidget(parent)
{
resize(640,480);
test1();
}
//父子关系
void test1()
{
//
int w=50;
int h=50;
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
auto lab=new QLabel(QString::number(j*2+i),this);
lab->setGeometry(j*w,i*h,w,h);
lab->setStyleSheet("background-color:red");
}
}
}
//获取鼠标点击
void mousePressEvent(QMouseEvent*ev)override
{
//获取指定位置控件
auto lab= this->childAt(mapFromGlobal(QCursor::pos()));
if(lab)
{
lab->setStyleSheet("background-color:yellow");
auto p=lab->parentWidget();
qInfo()<<p->childrenRect();
}
}
};