Qt 快速入门学习笔记

环境安装

  • 环境配置以及安装

安装包下载地址

1、windows安装

msvc编译器模块需要安装Windows软件开发工具包。

MinGW是Windows平台使用GNU工具导入库的集合。

2、Linux环境安装

双击.run文件即可

安装常用的开发依赖

apt-get install g++
apt-get install make
apt-get install libgl1-mesa-dev #gui运行依赖库

3、visual studio中创建Qt项目以及配置

1、工具安装

a、工具->扩展和更新->联机右上角搜索qt,下载安装Qt Visual Studio Tools

b、下载离线安装

配置Qt编译器版本:

1、点击Qt VS Tools选项 -> Qt Versions, 再弹出的框中添加对应的编译器版本

比如:D:\Qt\Qt5.12.12\5.12.12\msvc2017_64\bin

visual studio中开发qt程序打开控制台:

右键项目 -> 属性 -> 链接器 -> 系统 -> 子系统 修改为控制台 然后保存

基础配置以及原理

  • pro文件解析
QT       += core gui #项目依赖模块# qt版本大于4才加入widgets模块
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets# app表示项目是exe应,lib表示是库
TEMPLATE = app# 生成的可执行文件名称
TAEGET = “ceshi_demo”# 使用C++11标准
CONFIG += c++11# 设置头文件搜索路径
INCLUDEPATH += ../include# $$PWD是pro的目录
INCLUDEPATH += $$PWD/../include
message("pwd = "$$PWD)# 项目包含的源码
SOURCES += \dialog.cpp \main.cpp \widget.cpp# 项目包含的头文件
HEADERS += \dialog.h \widget.h# 项目包含的窗体文件
FORMS += \dialog.ui \widget.ui# 指定库引用路径和名称 -L库路径 -l库名
LIBS += -L"./lib" -ltest#修改可执行文件/目标文件输出路径
DESTDIR += ../buildqnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target# 项目资源文件
RESOURCES += \res.qrc#debug和release环境判断
CONFIG(debug,debug|release){TARGET = "ceshi_demo_debug"
} else {TARGET = "ceshi_demo_relsease"
}#跨平台编译配置 win32 linux macx unix
win32{message("win32")
}!win32{message("!win")
}win32|linux{message("win32|linux")
}# 查看编译器信息
message($$QMAKESPEC)# 查看编译器包括那些 D:\Qt\Qt5.12.12\5.12.12\mingw73_32\mkspecs# dll输出路径
DLLDESTDIR += "../bin"# 设置可执行程序图标 demo.ico存放在pro相同目录
RC_ICONS = demo.ico# OBJECTS_DIR 表示程序生成的中间临时文件的存放路径
# MOC_DIR  moc命令生成的临时文件路径
# RCC_DIR 用来描述qt资源编译器输出文件路径
  • pri文件

在中大型项目中用pri文件配置各个子项目的公共变量、公共编译选项、公共路径

# 用来在pro/pri中引入某pri文件 include空格()
include (../my.pri)# 环境变量 $${环境变量}#自定义变量
CUSTOM_PATH = "../../home"
  • Qt程序编译的步骤

1、编译pro生成makefile

2、jom或者make编译makefile

# 生成界面的源码
D:\Qt\Qt5.12.12\5.12.12\mingw73_32\bin\uic.exe widget.ui -o ui_widget.h
# 生成信号槽代码
D:\Qt\Qt5.12.12\5.12.12\mingw73_32\bin\moc.exe widget.h moc_widget.cppqmake -o makefile demo.pro
jom /f makefile.Debug #windows
make # linux/mac
  • Qt元对象系统

QObject类是所有元对象系统的类的基类

在一个类的private部分声明Q_OBJECT宏,使得类可以使用元对象的特性如动态属性、信号与槽

Q_PROPERTY()宏可以定义属性

QObject ob;
// 设置动态属性
ob.setProperty("name", "zhansan");
// 获取属性值
ob.property("name")

UI基础组件以及常用功能

  • Qt容器类

顺序容器类:QList、QLinkedList、QVector、QStack、QQueue

QList数组列表

QLinkedList链式列表

QVector动态数组的功能,支持迭代器和下标访问

QStack类似堆栈先进后出

QQueue类似队列的先入先出

关联容器类:QMap、QMultiMap、QHash、QMultiHash、QSet

QMultiMap、QMultiHash支持一个键关联多个值

QSet是基于散列表的集合模板类,存储无顺序、查找速度快,内部用QHash实现

QMap存储基于键值对,存储按照key的顺序,不在乎顺序用QHash更快

QHash基于散列表来实现字典功能的模板类

  • 信号与槽

类似windows的消息机制,信号函数只发送,不需要知道接受者,需要QObject来绑定。

原理:

1、绑定信号函数和槽函数

2、调用信号函数(将信号写入队列)

3、主线程从队列中获取信号,在信号线程中找到信号和槽关联的队列处理,调用槽函数

connect(sender, SIGNAL(signal), receiver, SLOT(slot));

1、一个信号可以连接多个槽

2、多个信号可以连接同一个槽

3、一个信号可以连接另外一个信号

4、信号与槽的参数个数需要一致,信号的参数不能少于槽的参数

5、信号与槽的类中需要加入Q_OBJECT

6、当信号发射时,与其关联的槽函数立即执行,当关联的槽函数执行完毕之后才能执行发射信号处后的代码

手动添加信号槽:

1、Q_OBJECT

2、手动创建信号signals

3、手动创建槽 public slots

  • QWidget

1、所用用户界面对象的基类

2、窗口部件接收鼠标、键盘等事件

3、屏幕上绘制自己

4、父子关系有相对坐标

手动创建QWidget对象
QWidget w;
w.show(); //显示包含子窗口
w.hide(); // 隐藏包含子窗口
w.geometry(); // 获取窗口坐标大小// 获取x.y.width.height
int x =  w.x();
int y = w.y();
int width = w.width();
int height = w.height();// 重新设置窗口大小、移动窗口位置
w.resize(300, 400);
w.move(0, 0);// 设置窗口状态  WindowMinimized  WindowFullScreen
setWindowState(Qt::WindowMaximized);// 同setWindowState效果
showNormal();
showMinimized();
showMaximized();
showFullScreen();// 去除界面边框和标题栏,无法缩放移动
//setWindowFlags(Qt::FramelessWindowHint);//  标题栏保留,去除所有按钮
setWindowFlags(Qt::WindowTitleHint | Qt::CustomizeWindowHint);
  • QString常用用法

QString中字符串是Unicode码,每一个字符是一个16位的QChar。所以处理中文没有问题。

// 1.字符串判空
QString str;
// QString str = nullptr;
str == ""
str.isNull()
str.isEmpty()// 2.字符串拼接 =+ 、append()
str += " end";// 3.格式化输出
QString str2 = QString("print %1 %2").arg("number = ").arg(45);
QString str3 = QString("格式化输出 %1, %2").arg(16, 0, 2).arg(255, 0, 16);
QString str;
str.sprintf("age is %d", 34);// 4.数字转QString
QString num = QString::number(35);// 5.字符串遍历
QString itstr = QString("hello, blob asfdfdasm fafasdfad");
// 方法一
for (QString::iterator itr = itstr.begin(); itr != itstr.end(); itr++) {qDebug() << *itr;
}
// 方法二
for (int i = 0; i<itstr.size(); i++) {qDebug() << itstr[i];
}// 6.字符串查找
// 从左往右
int location = itstr.indexOf("blob");
// 从后往前
int lastlocation = itstr.lastIndexOf("fa");// 7.字符串截断
// 截断后面几个字符
itstr.chop(4);
// 从左边截断n个字符
QString left = itstr.left(5);
QString right = itstr.right(5);// 8.字符串替换
itstr.replace("hello", "hahah");// 9.去掉字符串空格
QString str = QString(" were ewre   ewr  ");
// 去掉字符串首位空格
qDebug() << str.trimmed();
// 去掉字符串首位空格,中间有连续空格也用一个空格替换
qDebug() << str.simplified();// 10 字符串包含
str.contains("we");// 字符串以什么结尾
str.endsWith("we");
// 字符串以什么开头
str.startsWith("ss");

Qt中文乱码问题:

1、默认字符集设置(默认UTF-8)

2、文件字符集格式vs qtcreator中设置,vs中默认是gbk的编码

3、字符集转换QStringLiteral

// qt creator中输出中文
QString str = "中文测试";
qDebug() << str;// vscode中开发qt,输出中文
QString str1 = QStringLiteral("中文测试");
qDebug() << str1;// vscode中开发qt,输出中文
// 1.头文件中设置编码方式
#pragma execution_character_set("UTF-8")QString str = "中文测试";
qDebug() << str;// 2.文件编码为GBK
const char* src = "元数据是中文GBK,多字节数据存入QString";
QString str1 = QString::fromLocal8Bit(src);
qDebug() << str1;// 把QString转为gbk
std::cout << str1.toLocal8Bit().toStdString() << std::endl;QString s = QStringLiteral("测试");
//  win api调用QString作为参数
MessageBox(0, s.toStdWString().c_str(), L"标题", 0);
  • QLabel

显示文字、换行、样式设置字体、颜色、背景色、显示图片、播放gif动画

换行直接输入\n

label = new QLabel(Widget);
label->setObjectName(QString::fromUtf8("label"));
label->setGeometry(QRect(190, 320, 251, 101));
// 设置样式表
label->setStyleSheet(QString::fromUtf8("font: 14pt \"Algerian\";color: rgb(119, 51, 255);"));
// 播放gif
QMovie *mov = new QMovie("test.gif");
label->setMovie(mov);
  • QPushButton

事件设置、快捷键、样式设置

click()/click(bool)/pressed()/released()

// 设置按钮快捷键
ui->pushButton->setShortcut(tr("Ctrl+x"));
// 设置样式
pushButton->setStyleSheet(QString::fromUtf8("background-color: rgb(255, 255, 0);color: rgb(42, 74, 255);border-radius:10px"));
// hover样式设置
pushButton->setStyleSheet(QString::fromUtf8("QPushButton::hover{background-color: rgb(0, 0, 0);}\n"
"QPushButton::!hover{background-color: rgb(255, 255, 0);color: rgb(42, 74, 255);border-radius:10px;}"));
  • QLineEdit
QLineEdit *edit = new QLineEdit(this);
edit->setObjectName("edit");
// 占位文字
edit->setPlaceholderText(QString("中文测试2"));
edit->move(100, 30);
edit->resize(100, 80);
// 清除按钮
edit->setClearButtonEnabled(true);
edit->setMaxLength(10);
// 设置显示密码的显示模式
edit->setEchoMode(QLineEdit::Password);
edit->setStyleSheet(QString("color: rgb(170, 0, 0);border-raduis: 20px;"));
// 输入验证
//edit->setInputMask("00.00;_");
// 只读
//eiit->setReadOnly(true);
// 校验器
QDoubleValidator *validator = new QDoubleValidator();
validator->setRange(-100, 1000, 3);
edit->setValidator(validator);// returnPressed 有效触发信号
connect(edit, SIGNAL(returnPressed()), this, SLOT(returnPressedTest()));// 另外一个按钮事件里面获取相关数据
void Widget::on_pushButton_clicked()
{QLineEdit *eiit = findChild<QLineEdit*>("edit");// 获取内容qDebug() << eiit->text();
}
  • 遍历查找组件的子元素
QObjectList list = this->children();
for (int i = 0; i < list.size(); i++) {QObject* obj = list[i];const QMetaObject* metaObject = obj->metaObject();// 获取子元素类名QString className = metaObject->className();// 获取子元素objectNameqDebug() << obj->objectName();qDebug() << className;// 转化if(className == "QPushButton") {QPushButton *btn = qobject_cast<QPushButton*>(obj);qDebug() << "找到了QPushButton text = " << btn->text();}
}
  • 容器布局Layout
//sizeHint推荐尺寸只能重载修改
//size() 不包含边框的窗口大小//QSizePolicy::PolicyFlag
//GrowFlag 必要时可超过推荐
//ExpandFlag 尽可能的拓展
//ShrinkFlag 必要时可小于推荐
//IgnoreFlag 缺省大小被忽略//QVBoxLayout
// 垂直布局
QVBoxLayout *layout = new QVBoxLayout(this);
// 设置距离边框的边距
layout->setContentsMargins(10,20,30,40);
// 设置元素之间的间距
layout->setSpacing(30);QPushButton *btn = new QPushButton("btn1");
// 设置按钮size的策略 推荐的大小
btn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
layout->addWidget(btn);QPushButton *btn2 = new QPushButton("btn2");
btn2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
layout->addWidget(btn2);QPushButton *btn3 = new QPushButton("btn3");
// 忽略 大小尽量缩放
btn3->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
// 设置最大和最小值
btn3->setMaximumSize(300, 300);
btn3->setMinimumSize(50,50);
layout->addWidget(btn3);// QGridLayout
QGridLayout *layout = new QGridLayout(this);
// 设置间距
layout->setVerticalSpacing(20);
layout->setHorizontalSpacing(10);QPushButton *btn1 = new QPushButton("btn1");
layout->addWidget(btn1, 0, 0);QPushButton *btn2 = new QPushButton("btn2");
layout->addWidget(btn2, 0, 1);QPushButton *btn3 = new QPushButton("btn3");
layout->addWidget(btn3, 1, 0);QPushButton *btn4 = new QPushButton("btn4");
layout->addWidget(btn4, 1, 1);// QFormLayout
QFormLayout *layout = new QFormLayout(this);
layout->setVerticalSpacing(20);
layout->setHorizontalSpacing(10);QLineEdit *account = new QLineEdit();
layout->addRow(QString("账号"), account);QLineEdit *password = new QLineEdit();
layout->addRow(QString("密码"), password);QHBoxLayout *hLayout = new QHBoxLayout();
layout->addRow(hLayout);QPushButton *login = new QPushButton(QString("登录"));
hLayout->addWidget(login);connect(login, SIGNAL(clicked()), this, SLOT(test()));void Widget::test() {qDebug() << "test";QFormLayout *lay = qobject_cast<QFormLayout*>(this->layout());qDebug() << lay;
}
  • qDebug输出调试信息的方式
// 1
qDebug() << "state = " << state;
// 2
qDebug("message = %s", info);
// 3 自定义类输出到qDebug
// 4 将标准输出重定向为到文件qInstallMessageHandler()
  • QCheckBox、QButtonGroup
QString res = ui->checkBox->text();
qDebug() << res;
ui->checkBox1->setText("text");
//  快捷键
ui->checkBox->setShortcut(tr("x"));
// 选中状态
ui->checkBox->isChecked();
// 同一父组件中的box单选
ui->checkBox->setAutoExclusive(true);// QButtonGroup
QButtonGroup *group= new QButtonGroup(this);// .ui 拖拽生成box1
// 加组后默认变单选
group->addButton(ui->box1);
group->addButton(ui->box2);
group->addButton(ui->box3);// 单选变多选
group->setExclusive(false);
// 绑定信号
QObject::connect(group, SIGNAL(buttonClicked(QAbstractButton *)), this, SLOT(testClicked(QAbstractButton *)));
  • QRadioButton
QButtonGroup *group= new QButtonGroup(this);
group->setObjectName("group");
QRadioButton *radio1 = new QRadioButton("QRadioButton1");
QRadioButton *radio2 = new QRadioButton("QRadioButton2");
QRadioButton *radio3 = new QRadioButton("QRadioButton3");
group->addButton(radio1);
group->addButton(radio2);
group->addButton(radio3);QVBoxLayout *layout = new QVBoxLayout(this);for (int i = 0; i<group->buttons().size() ; i++) {layout->addWidget(group->buttons()[i]);
}// 获取选中的radioButton
QButtonGroup *group = findChild<QButtonGroup *>("group");
QRadioButton *radio = (QRadioButton *)group->checkedButton();
qDebug() << radio->text();
  • QComboBox

属性编辑、图标大小、插入数据(字符串、图标、自定义数据)、读取数据、信号事件

// 自定义数据处理
struct CustomType
{QString name;
};
Q_DECLARE_METATYPE(CustomType);// 清空之前的item
ui->comboBox->clear();
ui->comboBox->addItem("item1");
ui->comboBox->addItem("item2");
// 添加带图标的item 图标在资源文件中
QIcon icon(":/tt/image/install_logo.png");
ui->comboBox->addItem(icon, "item_icon");
// 添加自定义数据item
CustomType type;
type.name = "zhansan";
QVariant ant;
ant.setValue(type);
ui->comboBox->addItem("custom_item", ant);// 获取数据
QString res = ui->comboBox->itemText(0);
qDebug() << res;
// 获取自定义数据
QVariant ant = ui->comboBox->itemData(3);
CustomType type = ant.value<CustomType>();
qDebug() << type.name;
  • QSlider

常用属性、信号事件、样式设计、重载鼠标自定义事件

// 滑动槽的样式
QSlider::groove {border: 1px solid #999999;height:28px;background: rgba(155,155,155,200);border-radius: 10px;
}
// 滑块的样式
QSlider::handle {background: rgba(255,0,0,200);border-radius: 10px;width:20px;margin: -10px 0;
}// 剩余槽的样式
QSlider::add-page {background: rgba(255, 0, 0, 10);
}// 滑过的槽的样式
QSlider::sub-page {background: rgba(0, 255, 0, 30);
}

QSlider重载鼠标事件:

1、界面设计器添加自定义CustomSlider类,提升控件

2、覆写mousePressEvent

3、计算鼠标位置

// customSlider.h
#ifndef CUSTOMSLIDER_H
#define CUSTOMSLIDER_H#include <QSlider>
#include <QWidget>class CustomSlider : public QSlider
{
public:CustomSlider(QWidget *p = NULL);virtual void mousePressEvent(QMouseEvent *ev);
};#endif // CUSTOMSLIDER_H// customSlider.cpp
#include "customslider.h"
#include <QDebug>
#include <QMouseEvent>CustomSlider::CustomSlider(QWidget *p): QSlider(p)
{
}void CustomSlider::mousePressEvent(QMouseEvent *ev) {qDebug() << ev->pos().x();QSlider::mousePressEvent(ev);// 百分比double p = (double)ev->pos().x() / (double)width();int val = p*(maximum() - minimum()) + minimum();setValue(val);
}
  • QListWidget

基本属性、插入和获取选中内容、遍历和排序、在列表中显示其他控件

// 关闭 水平垂直滚动条
ui->listWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
ui->listWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
// 多选模式
//ui->listWidget->setSelectionMode(QAbstractItemView::MultiSelection);
//  设置方向
//ui->listWidget->setFlow(QListView::LeftToRight);
// 设置每一行的大小
//ui->listWidget->setGridSize(QSize(100, 50));
// 清除.ui中添加的数据
ui->listWidget->clear();
// 插入数据
QListWidgetItem *item = new QListWidgetItem("code insert");
ui->listWidget->addItem(item);
ui->listWidget->addItems({"item2","item 3", "item3"});// 插入包含图标的item
QListWidgetItem *item_icon = new QListWidgetItem("icon item");
item_icon->setIcon(QIcon(":/tt/image/install_logo.png"));
ui->listWidget->addItem(item_icon);// 遍历
for (int i = 0; i< ui->listWidget->count() ; i++) {qDebug() << ui->listWidget->item(i)->text();
}// 设置 双击为可编辑状态
ui->listWidget->setEditTriggers(QAbstractItemView::DoubleClicked);
for (int i = 0; i< ui->listWidget->count() ; i++) {ui->listWidget->item(i)->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable);
}// 排序
ui->listWidget->sortItems(Qt::DescendingOrder);// 添加其他控件
QLineEdit *edit = new QLineEdit("QLineEdit");
// item(0) 第一个组件替换为QLineEdit
ui->listWidget->setItemWidget(ui->listWidget->item(0), edit);
  • QTableWidget

常用属性设置、设置水平/垂直标题、插入数据、获取选中数据、删除、信号

// 清空所有标题和内容
ui->tableWidget->setColumnCount(0);
ui->tableWidget->setRowCount(0);ui->tableWidget->setColumnCount(4);
ui->tableWidget->setHorizontalHeaderItem(0, new QTableWidgetItem("header1"));
ui->tableWidget->setHorizontalHeaderItem(1, new QTableWidgetItem());
ui->tableWidget->horizontalHeaderItem(1)->setText("header2");ui->tableWidget->setHorizontalHeaderItem(2, new QTableWidgetItem("header3"));
ui->tableWidget->setHorizontalHeaderItem(3, new QTableWidgetItem("header4"));// 设置 第0列 标题的宽度
ui->tableWidget->setColumnWidth(0, 200);
// 设置垂直标题
ui->tableWidget->setRowCount(3);
QStringList list = {"col1", "col2", "col3"};
ui->tableWidget->setVerticalHeaderLabels(list);// 插入数据
ui->tableWidget->setItem(0,0, new QTableWidgetItem("col 0,0"));
ui->tableWidget->setItem(0,1, new QTableWidgetItem("col 0,1"));
ui->tableWidget->setItem(0,2, new QTableWidgetItem("col 0,2"));
ui->tableWidget->setItem(1,0, new QTableWidgetItem("col 1,0"));
ui->tableWidget->setItem(2,0, new QTableWidgetItem("col 2,0"));// 结尾添加一行
int row = ui->tableWidget->rowCount();
ui->tableWidget->insertRow(row);
ui->tableWidget->setItem(row, 0, new QTableWidgetItem("new row 4"));// 开始添加一行
ui->tableWidget->insertRow(0);
ui->tableWidget->setItem(0, 0, new QTableWidgetItem("new row 0"));// 插入图片
ui->tableWidget->setItem(0, 1, new QTableWidgetItem("new row 1 icon"));
ui->tableWidget->item(0, 1)->setIcon(QIcon(":/tt/image/install_logo.png"));
// 设置行高
ui->tableWidget->setRowHeight(0, 80);
// 设置图标显示大小
ui->tableWidget->setIconSize(QSize(ui->tableWidget->rowHeight(0), ui->tableWidget->rowHeight(0)));// 插入widght 图片
QLabel *label = new QLabel();
QPixmap pix(":/tt/image/install_logo.png");
// 缩放图片
pix = pix.scaled(ui->tableWidget->columnWidth(0), ui->tableWidget->rowHeight(row));
label->setPixmap(pix);
ui->tableWidget->setCellWidget(row, 0, label);// 如何获取选中的数据?
// 没有数据的item无法选择
auto items = ui->tableWidget->selectedItems();
for (int i = 0; i < items.size() ; i++ ) {qDebug() << "row = " << items[i]->row() << " col = " << items[i]->column() << " text = " << items[i]->text();
}// 选择模式器
QItemSelectionModel *mode = ui->tableWidget->selectionModel();
// 获取所有的选择索引
auto list = mode->selectedIndexes();
qDebug() << list;

样式:标题格式、间隔线、背景颜色间隔

// 标题样式
QHeaderView::section {background-color: rgb(60, 193, 255);color: white;padding-left: 4px;border: 1px solid #6c6c6c;
}
// 选中
QHeaderView::section:checked {background-color: rgb(255, 170, 0);
}// 悬停
QHeaderView::section:hover {background-color: red;
}
  • QTreeWidget

常用属性、标题、内容插入、内容选择、拖动和删除、信号事件

// 清理.ui中生成的标题
ui->treeWidget->setHeaderItem(new QTreeWidgetItem());
//  清理数据
ui->treeWidget->clear();ui->treeWidget->setColumnCount(3);// 设置标题
ui->treeWidget->headerItem()->setText(0, "header1");
ui->treeWidget->headerItem()->setText(1, "header2");
ui->treeWidget->headerItem()->setText(2, "header3");// 插入数据
// 从结尾处插入
ui->treeWidget->addTopLevelItem(new QTreeWidgetItem());
ui->treeWidget->topLevelItem(0)->setText(0, "tree node col1");
ui->treeWidget->topLevelItem(0)->setText(1, "tree node col2");ui->treeWidget->addTopLevelItem(new QTreeWidgetItem({"tree row1 col1", "tree row1 col2"}));// 开头插入
ui->treeWidget->insertTopLevelItem(0, new QTreeWidgetItem({"tree row0 col1", "tree row0 col2"}));// 结尾插入
ui->treeWidget->insertTopLevelItem(ui->treeWidget->topLevelItemCount(), new QTreeWidgetItem({"tree end col1"}));
// 结尾插入
QTreeWidgetItem *node = new QTreeWidgetItem(ui->treeWidget);
node->setText(0, "new end col1");// 插入子节点
ui->treeWidget->topLevelItem(0)->addChild(new QTreeWidgetItem({"child1"}));
ui->treeWidget->topLevelItem(0)->addChild(new QTreeWidgetItem({"child2"}));
ui->treeWidget->topLevelItem(0)->addChild(new QTreeWidgetItem({"child3"}));ui->treeWidget->topLevelItem(1)->addChild(new QTreeWidgetItem({"2 - child1"}));
ui->treeWidget->topLevelItem(1)->addChild(new QTreeWidgetItem({"2 - child2"}));// 插入孙节点
ui->treeWidget->topLevelItem(0)->child(1)->addChild(new QTreeWidgetItem({"grandSon"}));// 设置图标
ui->treeWidget->setIconSize(QSize(50, 50));
ui->treeWidget->topLevelItem(0)->setIcon(0, QIcon(":/tt/image/install_logo.png"));// 插入 widget
QPushButton *btn = new QPushButton("button");
ui->treeWidget->setItemWidget(ui->treeWidget->topLevelItem(1), 0, btn);// 设置颜色交错
ui->treeWidget->setAlternatingRowColors(true);

样式处理

// 行列样式
QTreeView {background-color:#fefff7;alternate-background-color: #cbe8d9;
}
QTreeView::item {border: 1px solid #c5daff;
}
// 选中和悬停的样式
QTreeView::item:hover {background: #c5daff;
}
QTreeView::item:selected {background: #debbe8;
}
// 标题样式
QTreeView::section {background-color: #ffe0d8;border: 1px solid #c5daff;
}

如何利用手册查看对应的样式示例:

点击帮助 -> 搜索 -> style sheeet -> Qt Style Sheets Examples -> 查找对应的控件设置详情

// 图片放在资源文件中
QTreeView::branch:has-siblings:!adjoins-item {border-image: url(":/tt/image/vline.png") 0;
}QTreeView::branch:has-siblings:adjoins-item {border-image: url(":/tt/image/branch-more.png") 0;
}QTreeView::branch:!has-children:!has-siblings:adjoins-item {border-image: url(":/tt/image/branch-end.png") 0;
}QTreeView::branch:has-children:!has-siblings:closed,
QTreeView::branch:closed:has-children:has-siblings {border-image: none;image: url(":/tt/image/branch-closed.png");
}QTreeView::branch:open:has-children:!has-siblings,
QTreeView::branch:open:has-children:has-siblings  {border-image: none;image: url(":/tt/image/branch-open.png");
}
  • QDialog

QDialog包括QColorDialog、QErrorMessage、QFileDialog、QFontDialog、QInputDialog、QMessageBox、QProgressDialog.

CustomDialog dialog;
dialog.setWindowTitle("dialog");
int result = dialog.exec();
switch (result) {case QDialog::Accepted:qDebug() << "Accepted";break;case QDialog::Rejected:qDebug() << "Rejected";break;default:break;;
}

自定义messagebox

// 添加qt设计师界面类
// 在界面中自定义ui
// 添加必要的信号槽// CustomMessageBox.h
#ifndef CUSTOMMESSAGEBOX_H
#define CUSTOMMESSAGEBOX_H#include <QDialog>namespace Ui {
class CustomMessageBox;
}class CustomMessageBox : public QDialog
{Q_OBJECTpublic:explicit CustomMessageBox(QWidget *parent = nullptr);~CustomMessageBox();static int info(QString msg);
private:Ui::CustomMessageBox *ui;
};#endif // CUSTOMMESSAGEBOX_H// CustomMessageBox.cpp
#include "custommessagebox.h"
#include "ui_custommessagebox.h"CustomMessageBox::CustomMessageBox(QWidget *parent) :QDialog(parent),ui(new Ui::CustomMessageBox)
{ui->setupUi(this);// 去掉标题栏setWindowFlags(Qt::FramelessWindowHint);// 设置背景透明this->setAttribute(Qt::WA_TranslucentBackground, true);
}CustomMessageBox::~CustomMessageBox()
{delete ui;
}int CustomMessageBox::info(QString msg)
{CustomMessageBox box;box.ui->label->setText(msg);return box.exec();
}// ui中添加了一个widght作为背景视图,添加一个label、两个按钮// 添加样式表,圆角
#widget {border-radius:30px;background-color: rgb(204, 204, 204);
}
Qdialog {border-radius:30px;background-color: rgb(204, 204, 204);border: 1px solid gray;
}

自定义processDialog进度条

// ProcessDialog.h
#include <QDialog>namespace Ui {
class ProcessDialog;
}class ProcessDialog : public QDialog
{Q_OBJECTpublic:explicit ProcessDialog(QWidget *parent = nullptr);~ProcessDialog();
public slots:void setDialog(int value);
private:Ui::ProcessDialog *ui;
};#endif// ProcessDialog.cpp
#include <QThread>ProcessDialog::ProcessDialog(QWidget *parent) :QDialog(parent),ui(new Ui::ProcessDialog)
{ui->setupUi(this);// 去掉标题栏和设置背景透明setWindowFlags(Qt::FramelessWindowHint);setAttribute(Qt::WA_TranslucentBackground, true);
}ProcessDialog::~ProcessDialog()
{delete ui;
}void ProcessDialog::setDialog(int value)
{ui->progressBar->setValue(value);if (value == 1000) {for (int i = 100; i > 0; i-- ) {this->setWindowOpacity((float)i / 100.0);QThread::msleep(5);// 设置label,shoudon
//            ui->label->setText(QString::number(i));
//            QEventLoop loop;
//            loop.processEvents();}this->close();}
}// 自定义多线程 CustomThread.h
#include <QThread>class CustomThread : public QThread
{Q_OBJECT
public:CustomThread();void run();signals:void setPos(int value);
};// CustomThread.cpp
void CustomThread::run()
{for(int i = 0; i <= 1000; i ++){setPos(i);msleep(10);}
}// 外部使用
ProcessDialog dialog;
CustomThread thread;
QObject::connect(&thread, SIGNAL(setPos(int)), &dialog, SLOT(setDialog(int)));
thread.start();
dialog.exec();
  • QMenuBar

QMenuBar、QMenu、QAction

// 插入菜单栏
QMenuBar *bar = new QMenuBar(this);
bar->resize(width(), bar->height());
// 一级菜单
QMenu *menu = bar->addMenu("菜单一");
m_menu = menu;// 二级菜单
QAction *action1 = menu->addAction("二级菜单1");
QAction *action2 = menu->addAction("二级菜单2");
QAction *action3 = menu->addAction("二级菜单3");
QMenu *menu1 = menu->addMenu("二级菜单4");
// 菜单设置图标
menu1->setIcon(QIcon(":/tt/image/install_logo.png"));
menu1->addAction("三级菜单");// 添加快捷键
action1->setShortcut(tr("x"));
// 绑定点击信号
connect(action1, SIGNAL(triggered()), this, SLOT(test()));
// 绑定鼠标悬停信号
connect(action2, SIGNAL(hovered()), this, SLOT(testHovered()));//  设置action可以选中
action1->setCheckable(true);
action2->setCheckable(true);
action3->setCheckable(true);// QActionGroup
QActionGroup *group = new QActionGroup(this);
group->addAction(action1);
group->addAction(action2);
group->addAction(action3);// 设置group中的按钮单选
group->setExclusive(true);// 鼠标位置显示菜单(用于动态显示创建好的菜单)
m_menu->exec(QCursor::pos());
  • QToolBar/QStatusBar
QToolBar *toolbar = new QToolBar(this);
toolbar->setGeometry(0, bar->height(), width(), 40);
toolbar->setIconSize(QSize(30, 30));
QAction *a = new QAction(QIcon(":/tt/image/install_logo.png"), "toolaction");
//a->setIcon(QIcon(":/tt/image/install_logo.png"));
toolbar->addAction(a);QStatusBar *statusBar = new QStatusBar(this);
statusBar->setGeometry(0, height() - 40, width(), 40);
statusBar->showMessage("测试status message", 3000);
  • MainWindow
menuBar()->addAction("menu1");
statusBar()->showMessage("status bar message");QToolBar *toolBar = new QToolBar(this);
toolBar->addAction("topaction");
QAction *a = new QAction(QIcon(":/tt/image/install_logo.png"), "icon action");
toolBar->addAction(a);
// 设置action text在icon下面
toolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
// 在左侧添加toolbar   Qt::LeftToolBarArea
addToolBar(Qt::TopToolBarArea, toolBar);
  • QT事件Event

事件函数event、鼠标事件、键盘事件、窗口大小变化事件、重绘事件QPainter

// QEvent子类 QKeyEvent、QMouseEvent、QWheelEvent、QTouchEventbool EventDemo::event(QEvent *ev)
{qDebug() << ev->type();// 键盘事件if (ev->type() == QEvent::KeyPress){QKeyEvent *keyEv = static_cast<QKeyEvent*>(ev);qDebug() << keyEv->key();// 代表处理,不会把事件传递给其他控件,继续处理下一个事件return true;}// 父类处理return QWidget::event(ev);
} // 键盘按下
void EventDemo::keyPressEvent(QKeyEvent *event)
{// 过滤自动重复触发的if(event->isAutoRepeat()) return;qDebug() << "keyPressEvent = " << event->key();
}// 键盘弹起
void EventDemo::keyReleaseEvent(QKeyEvent *event)
{qDebug() << "keyReleaseEvent = " << event->key();
}

鼠标事件

bool EventDemo::event(QEvent *ev)
{qDebug() << ev->type();// 鼠标事件if (ev->type() == QEvent::MouseButtonPress){QMouseEvent *event = static_cast<QMouseEvent*>(ev);// 相对坐标qDebug() << "QMouseEvent x = " << event->x() << " y = " << event->y();// 程序坐标qDebug() << "windowPos x = " << event->windowPos().x() << " y = " << event->windowPos().y();// 屏幕坐标qDebug() << "screenPos x = " << event->screenPos().x() << " y = " << event->screenPos().y();// 本地坐标转屏幕坐标QPoint point = mapToGlobal(event->pos());qDebug() << "mapToGlobal x = " << point.x() << " y = " << point.y();// 获取鼠标的屏幕坐标qDebug() << "QCursor x = " <<  QCursor::pos().x() << " y = " << QCursor::pos().y();// 鼠标按键事件if (event->buttons() & Qt::LeftButton){qDebug() << "LeftButton click";}if (event->buttons() & Qt::RightButton){qDebug() << "RightButton click";}if (event->buttons() & Qt::MidButton){qDebug() << "MidButton click";}if ((event->buttons() & Qt::LeftButton) && (event->buttons() & Qt::RightButton)){qDebug() << "LeftButton && RightButton click";}return true;}return QWidget::event(ev);
}

修改鼠标样式

QCursor cursor;
QPixmap map(":/tt/image/install_logo.png");
cursor = QCursor(map, -1, -1);
setCursor(cursor);//  还原
setCursor(Qt::ArrowCursor);

窗口大小改变事件

void EventDemo::resizeEvent(QResizeEvent *event)
{qDebug() << "resizeEvent";// 改变子控件的大小ui->pushButton->resize(width() * 0.3, height() * 0.3);
}
  • QPainter

绘制文字、绘制线、绘制图形、绘制融合图片

QPen用于控制线条的颜色、宽度、线型等

QBrush用于设置填充颜色、填充方式、渐变特性等,可以使用图片做填充

QFont用于绘制文字时设置文字的样式大小

void PainterDemo::paintEvent(QPaintEvent *event)
{// 设置绘制设备QPainter p(this);// 画笔颜色p.setPen(QColor(255,0,0,150));// 字体p.setFont(QFont("黑体", 20));p.drawText(100, 50, "绘制文字");// 绘制线QPen pen;// 实线pen.setStyle(Qt::SolidLine);// 线的宽度pen.setWidth(10);// 线刷子pen.setBrush(Qt::red);// 设置刷子为图片//pen.setBrush(QBrush(QImage(":/tt/image/install_logo.png")));// 结尾端样式pen.setCapStyle(Qt::RoundCap);// 连接处样式pen.setJoinStyle(Qt::RoundJoin);p.setPen(pen);p.drawLine(QLine(10, 10, 300, 90));}
  • QImage
QImageDemo::QImageDemo(QWidget *parent) :QWidget(parent),ui(new Ui::QImageDemo)
{ui->setupUi(this);img = QImage(1280, 720, QImage::Format_RGBA8888);// 填入颜色img.fill(QColor(255,0,0,200));// 遍历设置颜色uchar *data = img.bits();// 假定已对齐,不对齐就出错for (int i = 0; i < img.width() ; i++ ) {for (int j = 0; j < img.height() / 2 ; j++) {data[j * img.width() * 4 + i * 4] = 0; // rdata[j * img.width() * 4 + i * 4 + 1] = 255; // gdata[j * img.width() * 4 + i * 4 + 1] = 0; // bdata[j * img.width() * 4 + i * 4 + 1] = 255; // a}}for (int i = img.width() / 2; i < img.width() ; i++ ) {for (int j = 0; j < img.height() ; j++) {img.setPixelColor(i,j, QColor(0, 0, 0, 255));}}
}void QImageDemo::paintEvent(QPaintEvent *ev)
{QPainter p(this);if(!img.isNull()) {p.drawImage(0, 0, img);}
}
  • 文件系统

QIODevice:所有 I/O 设备类的父类,提供了字节块读写的通用操作以及基本接口;
QFileDevice:Qt5新增加的类,提供了有关文件操作的通用实现。
QFlie:访问本地文件或者嵌入资源;
QTemporaryFile:创建和访问本地文件系统的临时文件;
QBuffer:读写QbyteArray, 内存文件;
QProcess:运行外部程序,处理进程间通讯;
QAbstractSocket:所有套接字类的父类;
QTcpSocket:TCP协议网络数据传输;
QUdpSocket:传输 UDP 报文;
QSslSocket:使用 SSL/TLS 传输数据;

顺序访问设备:
是指它们的数据只能访问一遍:从头走到尾,从第一个字节开始访问,直到最后一个字节,中途不能返回去读取上一个字节,这其中,QProcess、QTcpSocket、QUdpSoctet和QSslSocket是顺序访问设备。
随机访问设备:
可以访问任意位置任意次数,还可以使用QIODevice::seek()函数来重新定位文件访问位置指针,QFile、QTemporaryFile和QBuffer是随机访问设备

QFile file("D:\\code\\123.txt");
// 获取当前目录
//QDir::currentPath()
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {qDebug() << "Open file failed.";return;
} else {while (!file.atEnd()) {qDebug() << file.readLine();}
}QFileInfo info(file);
qDebug() << info.isDir();
qDebug() << info.isExecutable();
qDebug() << info.baseName();
qDebug() << info.completeBaseName();
qDebug() << info.suffix();
qDebug() << info.completeSuffix();

QDataStream二进制文件读写

// 写入
QFile file("D:\\code\\123.txt");
if (!file.open(QIODevice::WriteOnly)) {qDebug() << "Open file failed.";return;
} else {QDataStream out(&file);out << QString("123");file.close();
}// 读取
QFile file("D:\\code\\123.txt");
if (!file.open(QIODevice::ReadOnly)) {qDebug() << "Open file failed.";return;
} else {// 读取QString res;QDataStream in(&file);in >> res;qDebug() << "res = " << res;file.close();
}

QTextStream文本文件读写

// 写入
QFile file("D:\\code\\123.txt");
if (!file.open(QIODevice::WriteOnly| QIODevice::Truncate)) {qDebug() << "Open file failed.";return;
} else {QTextStream out(&file);out.setCodec("UTF-8");// 写入一行换行out << QString("test message") << endl;out << QString("test message other");file.close();
}// 读取多行QFile file("D:\\code\\123.txt");
if (!file.open(QIODevice::ReadOnly)) {qDebug() << "Open file failed.";return;
} else {QTextStream in(&file);QString res;while (in.readLineInto(&res)) {qDebug() << res;}file.close();
}
  • Qt样式表

1、Qt样式表支持CSS2中定义的所有选择器

选择器 例子 用途
通用选择器 * 所有组件
类型选择器 QPushButton 所有QPushButton类及其子类
属性选择器 QPushButton[flat=“false”] 所有QPushButton属性flat=false的类及其子类
非子类选择器 .QPushButton 所有QPushButton类不包括其子类
ID选择器 QPushButton#btn ObjectName="btn"的QPushButton组件
从属对象选择器 QDialog QPushButton QDialog下面的所有QPushButton实例
子对象选择器 QDialog>QPushButton QDialog下面直接从属的所有QPushButton实例

2、子控件,组合组件下面的控件控制,例如QProgressBar::chunk 进度显示块的控制

3、伪状态的控制,如:hover

4、属性的控制 如:border

样式表的使用:

1、设计窗体中设置

2、setStyleSheet函数设置

多线程以及同步

  • QThread

基础使用

#ifndef CUSTOMTHREAD_H
#define CUSTOMTHREAD_H#include <QThread>class CustomThread : public QThread
{Q_OBJECT
public:CustomThread();void run();signals:void setPos(int value);
};#endif // CUSTOMTHREAD_H// cpp
#include "customthread.h"CustomThread::CustomThread()
{}void CustomThread::run()
{for(int i = 0; i <= 1000; i ++){// 发送信号,外面绑定信号处理setPos(i);msleep(10);}
}
  • 线程同步方案

1、基于互斥量的线程同步

QMutex、QMutexLocker 每次只有一个线程获得互斥量的权限

2、QReadWriteLock 适合用于一个线程写,多个线程获取的场景

3、QWaitCondition 适用于一个线程满足某个条件,然后通知其他线程响应的场景

4、基于信号量的线程同步 QSemaphore 适用于保护一定数量的资源

网络编程

  • 获取本机相关信息

QHostInfo、QNetworkInterface

// QT       += network// 电脑设备名称
QString hostName = QHostInfo::localHostName();
QString domainName = QHostInfo::localDomainName();
qDebug() << hostName;
qDebug() << domainName;QHostInfo host = QHostInfo::fromName(hostName);
// 获取地址列表
QList<QHostAddress> address = host.addresses();
for(int i = 0; i < address.size(); i++)
{qDebug() << address[i];if (address[i].protocol() == QAbstractSocket::IPv4Protocol) {qDebug() << "IPv4Protocol";} else {qDebug() << "IPv6Protocol";}
}// 获取主机网络接口
QList<QNetworkInterface> interface = QNetworkInterface::allInterfaces();
for(int i = 0; i < interface.size(); i++)
{// 设备名称qDebug() << interface[i].humanReadableName();// 设备地址qDebug() << interface[i].hardwareAddress();
}
  • 网络通信

QTcpSocket

QUdpSocket

QNetworkRequest、QNetworkRequest、QNetworkAccessManager

#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkAccessManager>
#include <QFile>
class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_readyRead();void on_finished();void on_process(qint64 current, qint64 totle);private:Ui::Widget *ui;QNetworkRequest request;QNetworkAccessManager manger;QNetworkReply *reply;QFile *downloadFile;
};
#endif // WIDGET_H// cppWidget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);QString urlString = "http://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png";QUrl url = QUrl::fromUserInput(urlString);if (!url.isValid()){qDebug() << "url error";return;}request = QNetworkRequest(url);reply = manger.get(request);connect(reply, SIGNAL(finished()), this, SLOT(on_finished()));connect(reply, SIGNAL(readyRead()), this, SLOT(on_readyRead()));connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(on_process(qint64,qint64)));QString fileName = QDir::currentPath() + "/" + url.fileName();qDebug() << "fileName = " << fileName;if (QFile::exists(fileName))QFile::remove(fileName);downloadFile = new QFile(fileName);downloadFile->open(QIODevice::ReadWrite);
}void Widget::on_readyRead()
{qDebug() << "on_readyRead";downloadFile->write(reply->readAll());
}
void Widget::on_finished()
{qDebug() << "on_finished";downloadFile->close();
}
void Widget::on_process(qint64 current, qint64 totle)
{qDebug() << "current = " << current << " totle = " << totle;
}

打包发布

  • 程序发布

静态发布:将所有的需要的运行库编译到应用程序中,生成独立的可执行文件

共享库形式发布:将程序依赖的共享库和可执行程序一起发布

  • windows平台程序打包

1、进入编译完成的release版本安装包目录

2、找到对应编译器的工具windeployqt

# D:\Qt\Qt5.12.12\5.12.12\msvc2017\bin
# windeployqt一般再对应的编译器bin目录下
# 打包程序 等待完成即可
# windeployqt并不能保证一次将所有的依赖都复制到对应的目录下,需要移除qt环境变量或者找个不包含qt环境的电脑测试,如果有缺失dll,将缺失的dll复制到对应的目录
D:\Qt\Qt5.12.12\5.12.12\msvc2017\bin\windeployqt.exe demo.exe

Qt 快速入门学习笔记相关推荐

  1. Java快速入门学习笔记9 | Java语言中的方法

    有人相爱,有人夜里开车看海,有人却连LeetCode第一题都解不出来!虽然之前系统地学习过java课程,但是到现在一年多没有碰过Java的代码,遇到LeetCode不知是喜是悲,思来想去,然后清空自己 ...

  2. Java快速入门学习笔记8 | Java语言中的数组

    有人相爱,有人夜里开车看海,有人却连LeetCode第一题都解不出来!虽然之前系统地学习过java课程,但是到现在一年多没有碰过Java的代码,遇到LeetCode不知是喜是悲,思来想去,然后清空自己 ...

  3. Java快速入门学习笔记7 | Java语言中的类与对象

    有人相爱,有人夜里开车看海,有人却连LeetCode第一题都解不出来!虽然之前系统地学习过java课程,但是到现在一年多没有碰过Java的代码,遇到LeetCode不知是喜是悲,思来想去,然后清空自己 ...

  4. Java快速入门学习笔记6 | Java语言中的for循环语句

    有人相爱,有人夜里开车看海,有人却连LeetCode第一题都解不出来!虽然之前系统地学习过java课程,但是到现在一年多没有碰过Java的代码,遇到LeetCode不知是喜是悲,思来想去,然后清空自己 ...

  5. Java快速入门学习笔记5 | Java语言中的while循环语句

    有人相爱,有人夜里开车看海,有人却连LeetCode第一题都解不出来!虽然之前系统地学习过java课程,但是到现在一年多没有碰过Java的代码,遇到LeetCode不知是喜是悲,思来想去,然后清空自己 ...

  6. Java快速入门学习笔记4 | Java语言中的if条件语句

    有人相爱,有人夜里开车看海,有人却连LeetCode第一题都解不出来!虽然之前系统地学习过java课程,但是到现在一年多没有碰过Java的代码,遇到LeetCode不知是喜是悲,思来想去,然后清空自己 ...

  7. Java快速入门学习笔记3 | Java语言中的表达式与操作符

    有人相爱,有人夜里开车看海,有人却连LeetCode第一题都解不出来!虽然之前系统地学习过java课程,但是到现在一年多没有碰过Java的代码,遇到LeetCode不知是喜是悲,思来想去,然后清空自己 ...

  8. Java快速入门学习笔记2 | Java语言中的基本类型

    有人相爱,有人夜里开车看海,有人却连LeetCode第一题都解不出来!虽然之前系统地学习过java课程,但是到现在一年多没有碰过Java的代码,遇到LeetCode不知是喜是悲,思来想去,然后清空自己 ...

  9. Java快速入门学习笔记1 | Eclipse使用

    有人相爱,有人夜里开车看海,有人却连LeetCode第一题都解不出来!虽然之前系统地学习过java课程,但是到现在一年多没有碰过Java的代码,遇到LeetCode不知是喜是悲,思来想去,然后清空自己 ...

最新文章

  1. mplayer最全的命令
  2. 列举在Web前端开发中经常会设置的特殊样式!
  3. java date dateformat_Java中SimpleDateFormat的使用方法
  4. 2021年10月到12月一个月学习总结2
  5. vim下更省心地用中文
  6. IEC 6-1131/3的5种标准编程语言
  7. java netbeans 教程_NetBeans 教程
  8. linux创建文件后会自动删除,linux会自动删除目录和文件的吗
  9. java验证只能输入数字和字母_java:为什么我做的验证只能验证数字和字母不重复,不能验证汉字不重复...
  10. 基于JAVA+SpringBoot+Mybatis+MYSQL的药房药品管理系统
  11. java 通过http post方式传参参数json 方式
  12. [acmm week12]染色(容斥定理+组合数+逆元)
  13. KEIL5 C51软件安装详细图文教程
  14. 你觉得让Android 开发所向往的高薪岗位有哪些?
  15. Android 界面一键变灰/黑白
  16. android仿QQ优雅的修改App字体大小
  17. python 判断一个list列表是否包含另一个list列表
  18. [C/C++后端开发学习] 7 tcp服务器的epoll实现以及Reactor模型
  19. 配置samba服务器@手把手
  20. 数学分析里面的蕴含(⇒)到底是什么意思

热门文章

  1. 卡拉OK歌词原理和实现高仿Android网易云音乐
  2. 揭秘“爆款级”产品!看葡萄城活字格低代码平台是如何诞生的
  3. 用Excel求线性回归方程
  4. 树莓派实现温控风扇智能降温
  5. 数据集大小与模型性能的敏感性分析
  6. java值面向对象2
  7. 阿维塔以情感智能陪伴用户“悦己而行”,为用户创造悦己生活
  8. 【狂神】HTML笔记
  9. 45页精华《2022中国建筑行业数字化转型研究报告》出炉(附下载)
  10. python字面量是什么_字面量是什么?