引言termux-x11 模式下支持的软件很少，但是好在有xfreerdp，这样的话，可以通过命令行来实现rdp的连接，但是记命令记不住，可视化的工具也没有，如果轻量使用，可以试试https://github.com/wyllianbs/xfreerdp-gui/，但是我为什么没有用这个呢？因为yad需要安装，apt尝试安装，不存在，源码编译yad又各种问题，后来又尝试zenity效果还不错，但是并不是我想要的，方案1--zenity#!/bin/bash # 获取用户输入的主要信息 USER_INPUT=$(zenity --forms \ --title="Remote Desktop Connection" \ --text="Enter the following details:" \ --separator="," \ --add-entry="Server Address" \ --add-entry="Username" \ --add-password="Password" \ --add-entry="Resolution (e.g., 1920x1080)" \ --add-combo="Color Depth (bpp)" --combo-values="8|16|24|32" \ --add-combo="Network" --combo-values="modem|broadband-low|broadband|broadband-high|wan|lan" \ --add-combo="Audio Mode" --combo-values="off|local|remote" \ --height=300) # 检查用户是否取消输入 if [ $? -ne 0 ]; then exit 1 fi # 解析用户输入 IFS=',' read -r SERVER USERNAME PASSWORD RESOLUTION BPP NETWORK AUDIO_MODE <<< "$USER_INPUT" # 获取用户输入的复选框选项 CHECKBOX_INPUT=$(zenity --list \ --title="Advanced Options" \ --text="Select the advanced options:" \ --separator="," \ --checklist \ --column="Select" --column="Option" \ TRUE "Dynamic Resolution" \ TRUE "Compression" \ TRUE "Glyph Cache" \ TRUE "Bitmap Cache" \ TRUE "Async Input" \ TRUE "Async Update" \ --height=300) # 检查用户是否取消输入 if [ $? -ne 0 ]; then exit 1 fi # 初始化选项参数 OPTIONS_ARRAY=() # 添加选项参数 $CHECKBOX_INPUT =~ "Dynamic Resolution" && OPTIONS_ARRAY+=("/dynamic-resolution") $CHECKBOX_INPUT =~ "Compression" && OPTIONS_ARRAY+=("/compression") $CHECKBOX_INPUT =~ "Glyph Cache" && OPTIONS_ARRAY+=("/gdi:hw") $CHECKBOX_INPUT =~ "Bitmap Cache" && OPTIONS_ARRAY+=("/bitmap-cache") $CHECKBOX_INPUT =~ "Async Input" && OPTIONS_ARRAY+=("/async-input") $CHECKBOX_INPUT =~ "Async Update" && OPTIONS_ARRAY+=("/async-update") # 生成完整的 xfreerdp 命令 COMMAND="xfreerdp /v:$SERVER /u:$USERNAME /p:$PASSWORD /size:$RESOLUTION /bpp:$BPP /network:$NETWORK ${OPTIONS_ARRAY[*]} /audio-mode:$AUDIO_MODE" # 执行 xfreerdp 命令 eval $COMMAND方案2--qtUI代码<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>MainWindow</class> <widget class="QMainWindow" name="MainWindow"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>421</width> <height>341</height> </rect> </property> <widget class="QWidget" name="centralwidget"> <layout class="QVBoxLayout" name="verticalLayout"> <item> <widget class="QTabWidget" name="tabWidget"> <property name="currentIndex"> <number>0</number> </property> <widget class="QWidget" name="tab"> <attribute name="title"> <string>Normal Options</string> </attribute> <layout class="QGridLayout" name="gridLayout_2"> <item row="0" column="0"> <widget class="QScrollArea" name="scrollArea_2"> <property name="widgetResizable"> <bool>true</bool> </property> <widget class="QWidget" name="scrollAreaWidgetContents_2"> <property name="geometry"> <rect> <x>0</x> <y>-20</y> <width>365</width> <height>262</height> </rect> </property> <layout class="QGridLayout" name="gridLayout_5"> <item row="0" column="0" rowspan="2" colspan="2"> <layout class="QGridLayout" name="gridLayout"> <item row="5" column="1" colspan="3"> <widget class="QComboBox" name="resolution_comboBox"> <item> <property name="text"> <string>800x600</string> </property> </item> <item> <property name="text"> <string>1024x760</string> </property> </item> <item> <property name="text"> <string>1280x600</string> </property> </item> <item> <property name="text"> <string>1360x768</string> </property> </item> <item> <property name="text"> <string>1440x900</string> </property> </item> <item> <property name="text"> <string>1600x900</string> </property> </item> <item> <property name="text"> <string>1920x1080</string> </property> </item> <item> <property name="text"> <string>1920x1200</string> </property> </item> </widget> </item> <item row="7" column="1" colspan="3"> <widget class="QComboBox" name="network_comboBox"> <item> <property name="text"> <string>auto</string> </property> </item> <item> <property name="text"> <string>modem</string> </property> </item> <item> <property name="text"> <string>broadband-low</string> </property> </item> <item> <property name="text"> <string>broadband</string> </property> </item> <item> <property name="text"> <string>broadband-high</string> </property> </item> <item> <property name="text"> <string>wan</string> </property> </item> <item> <property name="text"> <string>lan</string> </property> </item> </widget> </item> <item row="5" column="0"> <widget class="QLabel" name="label_4"> <property name="text"> <string>Resolution</string> </property> </widget> </item> <item row="8" column="0"> <widget class="QLabel" name="label_7"> <property name="text"> <string>Audio Mode</string> </property> </widget> </item> <item row="8" column="1" colspan="3"> <widget class="QComboBox" name="audio_comboBox"> <item> <property name="text"> <string>off</string> </property> </item> <item> <property name="text"> <string>local</string> </property> </item> <item> <property name="text"> <string>remote</string> </property> </item> </widget> </item> <item row="6" column="0"> <widget class="QLabel" name="label_5"> <property name="text"> <string>Color Depth(bpp)</string> </property> </widget> </item> <item row="1" column="0"> <widget class="QLabel" name="label"> <property name="text"> <string>Host</string> </property> </widget> </item> <item row="7" column="0"> <widget class="QLabel" name="label_6"> <property name="text"> <string>Network</string> </property> </widget> </item> <item row="4" column="0"> <widget class="QLabel" name="label_3"> <property name="text"> <string>Password</string> </property> </widget> </item> <item row="3" column="1" colspan="3"> <widget class="QLineEdit" name="username_text"/> </item> <item row="1" column="1"> <widget class="QLineEdit" name="host_text"/> </item> <item row="1" column="3"> <widget class="QLineEdit" name="port_text"> <property name="maximumSize"> <size> <width>60</width> <height>16777215</height> </size> </property> <property name="text"> <string>3389</string> </property> </widget> </item> <item row="3" column="0"> <widget class="QLabel" name="label_2"> <property name="text"> <string>UserName</string> </property> </widget> </item> <item row="1" column="2"> <widget class="QLabel" name="label_18"> <property name="text"> <string>:</string> </property> </widget> </item> <item row="4" column="1" colspan="3"> <widget class="QLineEdit" name="password_text"/> </item> <item row="6" column="1" colspan="3"> <widget class="QComboBox" name="bpp_comboBox"> <item> <property name="text"> <string>8</string> </property> </item> <item> <property name="text"> <string>16</string> </property> </item> <item> <property name="text"> <string>24</string> </property> </item> <item> <property name="text"> <string>32</string> </property> </item> </widget> </item> <item row="2" column="0"> <widget class="QLabel" name="label_19"> <property name="text"> <string>Domain</string> </property> </widget> </item> <item row="2" column="1" colspan="3"> <widget class="QLineEdit" name="domain_text"/> </item> </layout> </item> </layout> </widget> </widget> </item> </layout> </widget> <widget class="QWidget" name="tab_2"> <attribute name="title"> <string>Advanced Options</string> </attribute> <layout class="QGridLayout" name="gridLayout_3"> <item row="0" column="0"> <widget class="QScrollArea" name="scrollArea"> <property name="widgetResizable"> <bool>true</bool> </property> <widget class="QWidget" name="scrollAreaWidgetContents"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>365</width> <height>365</height> </rect> </property> <layout class="QGridLayout" name="gridLayout_4"> <item row="1" column="0"> <layout class="QFormLayout" name="formLayout"> <item row="1" column="0"> <widget class="QLabel" name="label_8"> <property name="text"> <string>Dynamic Resolution</string> </property> </widget> </item> <item row="2" column="0"> <widget class="QLabel" name="label_9"> <property name="text"> <string>Compression</string> </property> </widget> </item> <item row="3" column="0"> <widget class="QLabel" name="label_10"> <property name="text"> <string>Glyph Cache</string> </property> </widget> </item> <item row="4" column="0"> <widget class="QLabel" name="label_11"> <property name="text"> <string>Bitmap Cache</string> </property> </widget> </item> <item row="5" column="0"> <widget class="QLabel" name="label_12"> <property name="text"> <string>Async Input</string> </property> </widget> </item> <item row="6" column="0"> <widget class="QLabel" name="label_13"> <property name="text"> <string>Async Update</string> </property> </widget> </item> <item row="1" column="1"> <widget class="QCheckBox" name="dynamic_resolution_box"> <property name="text"> <string>Enable</string> </property> <property name="checked"> <bool>true</bool> </property> </widget> </item> <item row="2" column="1"> <widget class="QCheckBox" name="compression_box"> <property name="text"> <string>Enable</string> </property> <property name="checked"> <bool>true</bool> </property> </widget> </item> <item row="3" column="1"> <widget class="QCheckBox" name="glyph_cache_box"> <property name="text"> <string>Enable</string> </property> <property name="checked"> <bool>true</bool> </property> </widget> </item> <item row="4" column="1"> <widget class="QCheckBox" name="bitmap_cache_box"> <property name="text"> <string>Enable</string> </property> <property name="checked"> <bool>true</bool> </property> </widget> </item> <item row="5" column="1"> <widget class="QCheckBox" name="async_input_box"> <property name="text"> <string>Enable</string> </property> <property name="checked"> <bool>true</bool> </property> </widget> </item> <item row="6" column="1"> <widget class="QCheckBox" name="async_update_box"> <property name="text"> <string>Enable</string> </property> <property name="checked"> <bool>true</bool> </property> </widget> </item> <item row="8" column="0"> <widget class="QLabel" name="label_14"> <property name="text"> <string>Share Direcory</string> </property> </widget> </item> <item row="8" column="1"> <widget class="QLineEdit" name="share_directory_text"/> </item> <item row="7" column="0"> <widget class="QLabel" name="label_15"> <property name="text"> <string>Shared Directory Name</string> </property> </widget> </item> <item row="7" column="1"> <widget class="QLineEdit" name="shared_directory_name_text"> <property name="text"> <string>Shared</string> </property> </widget> </item> <item row="0" column="0"> <widget class="QLabel" name="label_16"> <property name="text"> <string>Full Screen</string> </property> </widget> </item> <item row="0" column="1"> <widget class="QCheckBox" name="full_screen_box"> <property name="text"> <string>Enable</string> </property> </widget> </item> <item row="9" column="0"> <widget class="QLabel" name="label_17"> <property name="text"> <string>Other Options</string> </property> </widget> </item> <item row="9" column="1"> <widget class="QTextEdit" name="other_options_text"> <property name="minimumSize"> <size> <width>0</width> <height>80</height> </size> </property> </widget> </item> </layout> </item> </layout> </widget> </widget> </item> </layout> </widget> <widget class="QWidget" name="tab_3"> <attribute name="title"> <string>Help</string> </attribute> <layout class="QGridLayout" name="gridLayout_6"> <item row="0" column="0"> <widget class="QTextBrowser" name="textBrowser"/> </item> </layout> </widget> </widget> </item> <item> <layout class="QHBoxLayout" name="horizontalLayout"> <item> <spacer name="horizontalSpacer"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>40</width> <height>20</height> </size> </property> </spacer> </item> <item> <widget class="QPushButton" name="cancel_button"> <property name="text"> <string>Cancel</string> </property> </widget> </item> <item> <widget class="QPushButton" name="connect_button"> <property name="text"> <string>Connect</string> </property> </widget> </item> </layout> </item> </layout> </widget> </widget> <tabstops> <tabstop>host_text</tabstop> <tabstop>port_text</tabstop> <tabstop>domain_text</tabstop> <tabstop>username_text</tabstop> <tabstop>password_text</tabstop> <tabstop>resolution_comboBox</tabstop> <tabstop>bpp_comboBox</tabstop> <tabstop>network_comboBox</tabstop> <tabstop>audio_comboBox</tabstop> <tabstop>full_screen_box</tabstop> <tabstop>dynamic_resolution_box</tabstop> <tabstop>compression_box</tabstop> <tabstop>glyph_cache_box</tabstop> <tabstop>bitmap_cache_box</tabstop> <tabstop>async_input_box</tabstop> <tabstop>async_update_box</tabstop> <tabstop>shared_directory_name_text</tabstop> <tabstop>share_directory_text</tabstop> <tabstop>other_options_text</tabstop> <tabstop>connect_button</tabstop> <tabstop>cancel_button</tabstop> <tabstop>scrollArea</tabstop> <tabstop>textBrowser</tabstop> <tabstop>scrollArea_2</tabstop> <tabstop>tabWidget</tabstop> </tabstops> <resources/> <connections/> </ui>mainwindow.h#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); void GetDefault(); private slots: void on_cancel_button_clicked(); void on_connect_button_clicked(); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_Hmainwindow.cpp#include "mainwindow.h" #include "ui_mainwindow.h" #include <QApplication> #include <QScreen> #include <QMessageBox> #include <QDebug> #include <QProcess> void MainWindow::GetDefault(){ QScreen *screen = QGuiApplication::primaryScreen(); QRect geometry = screen->geometry(); int screenWidth = geometry.width(); int screenHeight = geometry.height(); QString current= QString("%1x%2").arg(screenWidth).arg(screenHeight); int idx = ui->resolution_comboBox->findText(current); if(idx >= 0){ ui->resolution_comboBox->setCurrentIndex(idx); }else{ ui->resolution_comboBox->insertItem(0,current); ui->resolution_comboBox->setCurrentIndex(0); } QProcess process; process.start("xfreerdp --help"); process.waitForFinished(); QByteArray output = process.readAllStandardOutput(); if (process.exitCode() != 0) { ui->textBrowser->setText("You need to install xfreerdp!"); QMessageBox::warning(this,"NOT FOUND XFREERDP", "You need to install xfreerdp!",QMessageBox::Yes); exit(0); }else{ ui->textBrowser->setText(QString::fromLocal8Bit(output).trimmed()); } } MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); ui->port_text->setValidator(new QRegExpValidator(QRegExp("[0-9]{5}"))); GetDefault(); } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_cancel_button_clicked() { exit(0); } void MainWindow::on_connect_button_clicked() { QString host = ui->host_text->text(); QString port = ui->port_text->text(); QString domain = ui->domain_text->text(); QString username = ui->username_text->text(); QString password = ui->password_text->text(); QString resolution = ui->resolution_comboBox->currentText(); QString bpp = ui->bpp_comboBox->currentText(); QString network= ui->network_comboBox->currentText(); QString audio_mode= ui->audio_comboBox->currentText(); bool full_screen = ui->full_screen_box->isChecked(); bool dynamic_resolution = ui->dynamic_resolution_box->isChecked(); bool compression = ui->compression_box->isChecked(); bool glyph_cache = ui->glyph_cache_box->isChecked(); bool bitmap_cache = ui->bitmap_cache_box->isChecked(); bool async_input = ui->async_input_box->isChecked(); bool async_update = ui->async_update_box->isChecked(); QString shared_directory_name_text = ui->shared_directory_name_text->text(); QString share_directory_text = ui->share_directory_text->text(); QString other_options_text = ui->other_options_text->toPlainText(); QString exec_command = ""; exec_command += QString("/v:'%1':%2").arg(host).arg(port); exec_command += domain!="" ? QString(" /d:'%1'").arg(domain) :"" ; exec_command += QString(" /u:'%1'").arg(username); exec_command += QString(" /p:'%1'").arg(password); exec_command += QString(" /size:%1").arg(resolution); exec_command += QString(" /bpp:%1").arg(bpp); exec_command += QString(" /network:%1").arg(network); exec_command += QString(" /audio-mode:%1").arg(audio_mode); exec_command += full_screen ? " /f" : ""; exec_command += dynamic_resolution ? " /dynamic-resolution" : ""; exec_command += compression ? " /compression" : ""; exec_command += glyph_cache ? " +glyph-cache" : ""; exec_command += bitmap_cache ? " /bitmap-cache" : ""; exec_command += async_input ? " /async-input" : ""; exec_command += async_update ? " /async-update" : ""; exec_command += (!shared_directory_name_text.isEmpty() && !share_directory_text.isEmpty()) ? QString(" /drive:%1,%2").arg(shared_directory_name_text).arg(share_directory_text) : ""; exec_command += QString(" %1").arg(other_options_text); QString program = "xfreerdp"; QString command = QString("%1 %2").arg(program).arg(exec_command); qDebug()<<command; QByteArray byteArray = command.toLocal8Bit(); const char *cmd = byteArray.constData(); int result = system(cmd); }main.cpp#include "mainwindow.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }
引言安装新版本的qt不再支持离线安装了，只能用在线的安装器安装，然而服务器在境外（有一个在芬兰），下载速度真的是泪崩呀。参数列表Usage: qt-unified-windows-x64-4.6.0-online.exe [options] command <args> <key=value> Qt Installer Framework supports both GUI and headless mode. The installation operations can be invoked with the following commands and options. Note that the options marked with "CLI" are available in the headless mode only. Commands: in, install - install default or selected packages - <pkg ...> ch, check-updates - show available updates information on maintenance tool up, update - update all or selected packages - <pkg ...> rm, remove - uninstall packages and their child components - <pkg ...> li, list - list currently installed packages - <regexp> se, search - search available packages - <regexp> Note: The --filter-packages option can be used to specify additional filters for the search operation co, create-offline - create offline installer from selected packages - <pkg ...> cc, clear-cache - clear contents of the local metadata cache pr, purge - uninstall all packages and remove entire program directory Options: -?, -h, --help Displays help on commandline options. --help-all Displays help including Qt specific options. -v, --version Displays version information. -d, --verbose Verbose mode. Prints out more information. Adding -d or --verbose more than once increases verbosity. -g, --logging-rules <rules> Enables logging according to passed rules. Comma separated logging rules have the following syntax: loggingCategory=true/false. Passing empty logging rules enables all logging categories. The following rules enable a single category: ifw.*=false, ifw.category=true. The following logging categories are available: ifw.installer.installlog ifw.server --ar, --add-repository <URI,...> Add a local or remote repository to the list of user defined repositories. --at, --add-temp-repository <URI,...> Add a local or remote repository to the list of temporary available repositories. --st, --set-temp-repository <URI,...> Set a local or remote repository as temporary repository, it is the only one used during fetch. Note: URI must be prefixed with the protocol, i.e. file:///, https://, http:// or ftp://. --sp, --system-proxy Use system proxy on Windows and Linux. This option has no effect on macOS. (Default) --np, --no-proxy Do not use system proxy. --su, --start-updater Start application in updater mode. This will override the internal marker that is used to distinguish which kind of binary is currently running. --sm, --start-package-manager Start application in package manager mode. This will override the internal marker that is used to distinguish which kind of binary is currently running. --sr, --start-uninstaller Start application in uninstaller mode. This will override the internal marker that is used to distinguish which kind of binary is currently running. -t, --root <directory> [CLI] Set installation root directory. --oi, --offline-installer-name <filename> [CLI] Set custom filename for the generated offline installer. Without this the original filename is used with an added "_offline-yyyy-MM-dd" suffix. -p, --platform <plugin> Use the specified platform plugin. --nf, --no-force-installations Allow deselecting components that are marked as forced. --nd, --no-default-installations Deselects components that are marked as default. --ns, --no-size-checking Disable checking of free space for installation target. --sv, --show-virtual-components Show virtual components in installer and package manager. -i, --install-compressed-repository <URI,...> Installs QBSP or 7z file. The QBSP (Board Support Package) file must be a .7z file which contains a valid repository. --cl, --create-local-repository Create a local repository inside the installation directory. This option has no effect on online installers. --fp, --filter-packages <element=regex,...> [CLI] Comma separated list of additional key-value pair filters used to query packages with the search command. The keys can be any of the possible package information elements, like "DisplayName" and "Description". --cp, --cache-path <path> Sets the path used for local metadata cache. The path must be writable by the current user. --am, --accept-messages [CLI] Accepts all message queries without user input. --rm, --reject-messages [CLI] Rejects all message queries without user input. --aa, --auto-answer <identifier=value> [CLI] Automatically answers the message queries with the message identifier and button value. Several identifier=value pairs can be given separated with comma, for example --auto-answer message.id=Ok,message.id2=Cance l. --da, --default-answer [CLI] Automatically answers to message queries with their default values. --al, --accept-licenses [CLI] Accepts all licenses without user input. --file-query <identifier=value> [CLI] Automatically sets the QFileDialog values getExistingDirectory() or getOpenFileName() requested by install script. Several identifier=value pairs can be given separated with comma, for example --file-query filedialog.id=C:/Temp,filedialo g.id2=C:/Temp2 -c, --confirm-command [CLI] Confirms starting of installation, update or removal of components without user input. -s, --script <file> Execute the script given as argument. --ss, --start-server <mode, socketname, key> Starts the application as headless process waiting for commands to execute. Mode can be DEBUG or PRODUCTION. In DEBUG mode, the option values can be omitted. Note: The server will not shutdown on his own, you need to quit the process by hand. --sc, --start-client <socketname, key> Starts the application to debug the client-server communication. If a value is omitted, the client will use a default instead. Note: The server process is not started by the client application in that case, you need to start it on your own. -q, --squish-port <port number> Give a port where Squish can connect to. If no port is given, attach to squish not done. Note: To enable Squish support you first need to build IFW with SQUISH_PATH parameter where SQUISH_PATH is pointing to your Squish installation folder: <path_to_qt>/bin/qmake -r SQUISH_PATH=<pat_to_squish> --mco, --max-concurrent-operations <threads> Specifies the maximum number of threads used to perform concurrent operations in the unpacking phase of components. Set to a positive number, or 0 (default) to let the application determine the ideal thread count from the amount of logical processor cores in the system. -m, --email <email> [CLI] Email used for Qt Account login. --pw, --password <password> [CLI] Password used for Qt Account login. --ra, --reset-qtaccount Erase Qt Account information from disk. --ao, --accept-obligations [CLI] Accepts Qt Open Source usage obligations without user input. --mirror <mirror> Uses the given mirror url for opensource downloads. --no-save-account, --na Does not save the Qt Account information to a file. --lk, --license-keys <KEY,...> Uses the given license keys in offline installers. Optional for Qt Account. --lu, --license-user <user> [CLI] User name for the license keys. Used together with --lk or --license-keys --pu, --proxy-url <url> [CLI] Proxy url for server. Used only when creating an offline installer with site license information. Arguments: Command Command to be run by installer. Note that this feature may be disabled by vendor. Args Extra arguments for command, each separated by space. InstallerValue Key-value pair to be set internally by the framework.指定镜像源实际上很简单，就是启动时，不要双击打开，用命令行添加参数即可。qt-unified-windows-x64-4.6.0-online.exe --mirror https://mirrors.tuna.tsinghua.edu.cn/qt/镜像列表中国科学技术大学：http://mirrors.ustc.edu.cn/qtproject/清华大学：https://mirrors.tuna.tsinghua.edu.cn/qt/北京理工大学：http://mirrors.bit.edu.cn/qtproject/阿里云：https://mirrors.aliyun.com/qt/中国互联网络信息中心：https://mirrors.cnnic.cn/qt/
QT (c++语言) - pro文件中定义的属性在代码中使用
引言比如在程序中显示版本信息和编译时间，这时候我们虽然可以每次打包时修改，但是还是比较麻烦，通过这种方式可以修改一个地方，其他地方就不用管了，相当于配置文件。代码参考：在pro文件中添加以下内容VERSION = 1.0.5 DEFINES += APP_VERSION=\\\"$$VERSION\\\" DEFINES += APP_WEBSITE=\\\"www.zunmx.top\\\" DEFINES += APP_COPYRIGHT=__DATE__ DEFINES += APP_COMPILE=__TIME__其中version和属性中是一样的，如果需要引用定义的变量，前面加上$$，当然也可以使用常量和内置函数，比如说日期和时间。在代码中直接使用即可const QString PRODUCT_VERSION=APP_VERSION; const QString COPYRIGHT = QString("%1").arg(APP_COPYRIGHT).split(" ")[2]; const QString WEBSITE = APP_WEBSITE; const QString BUILD_DATE = QString("%1 %2").arg(QLocale(QLocale::English).toDateTime(APP_COPYRIGHT, "MMM dd yyyy").toString("yyyy-MM-dd")).arg(APP_COMPILE);
引言QT项目打包后添加版权信息，文件说明等代码在pro文件中添加以下信息VERSION = 1.0.5 //版本信息 RC_LANG = 0x0004 // 语言，中文 RC_ICONS = icon.ico // 程序图标 QMAKE_TARGET_COPYRIGHT = "Copyright ZunMX All rights reserved." // 版权 QMAKE_TARGET_DESCRIPTION = "A recording program for system usage" // 文件说明 QMAKE_TARGET_COMPANY = " ZunMX " // 公司 QMAKE_TARGET_PRODUCT = " KMU-Counter " // 产品名称尝试了修改pro编码和msvc的编码，中文部分还是会乱码，暂时不知道如何解决。
KMU-Counter软件名称：KMU-Counter软件最新版本：1.1.5版本标识：正式版发布时间：2025-08-15编程语言：c++架构：QT适用平台：Windows权限申请● 本地文件读/写 (用于SQLite数据库操作)● 监控鼠标/键盘操作 (用于基础数据支撑)● 窗口信息获取 (用于基础数据支撑)● 网络通讯权限 (用于获取更新)● 获取屏幕截图 (可自选关闭)使用文档[post cid="1918" cover="" size=""/]授权许可证未注册和注册用户目前是相同的功能，只是未授权的用户每次启动时会弹出授权窗口。授权码可以通过联系管理员admin@zunmx.top，进行试用或~购买~。自助试用授权页面目前尚未开发完成。[font color="#10FF10"]软件内提供license.txt，授权到期至2023年12月31日[1.1.3-:)版本提供至2024-06-01的试用许可证[/font]邮箱：demo@zunmx.top 注册码：[binary] 有效期至：2026-12-31 23:59:59截图[collapse status="true" title="新版增量截图"][album type="photos"][/album][/collapse][collapse status="false" title="初版归档"][album type="photos"][/album][/collapse]更新日志[collapse status="true" title="v1.1.6"]发布日期：待定[💥] 修复了部分日期格式化问题[💥] 修复了句柄泄露问题，提高程序稳定性[💥] 修复了一些情况下窗体记录失败[💥] 修复了部分模块的缓冲区溢出问题[💥] 修复了锁屏时重叠记录[🚩] 新增UI键盘展示次数（实验性功能）[🚩] 新增托盘图标的提示文字[🎈] 升级QT版本至6.10.0[🎈] 升级openssl版本至3.5.4[🎈] 优化屏幕截图逻辑，支持多监视器[🎈] 屏幕截图格式png变更jpg，质量75，减小占用[🎈] 日志输出更加友好[🎈] 窗体标题获取不到时用类名代替(CN:[xxx])[/collapse][collapse status="true" title="v1.1.5"]发布日期：2025-8-15[💥] SHIFT按抬起次数统计异常的bug[💥] 锁屏时间和锁屏前的窗口重叠记录[💥] 重复运行时样式丢失[🚩] 新增打开文件所在目录[🚩] 新增删除图标缓存[🎈] 更换安装器，压缩安装包体积(但是无法检测更新，样式不那么好看了)[🎈] 升级QT版本至6.9.0[🎈] 更新OpenSSL至3.4.0[/collapse][collapse status="true" title="v1.1.4"]发布日期：2024-01-31[💥] 删除历史记录时提示未选择类别bug[🚩] 新增批量删除使用记录(按标题)[🚩] 新增批量复制使用记录(按标题)[🚩] 新增锁定功能 (轻度防卫) 【需授权】[🎈] 总统计持续时间格式化为日时分秒[🎈] 总统计切换时loading状态异常[/collapse][collapse status="true" title="v1.1.3"]发布日期：2023-12-22[💥] 类别筛选数据不正确[💥] 视图转换后自动跳转至最新日期[💥] 部分情况下存在注入问题导致无法持久化[💥] 程序图标获取异常bug修复[🎈] 调试版本明显标识 [此版本仅限开发][🎈] 升级QT版本至6.61[/collapse][collapse status="true" title="v1.1.2"]发布日期：2023-10-31[💥] 部分应用无法记录（已知红警2游戏）[🔧特殊符号][💥] 初始化数据库异常[💥] 统计导出缺失数据[💥] 总统计键盘活动次数数据异常[🚩] 新增类别统计 [🎉终于来啦][🚩] 添加了按键记录逻辑选项（实际输入和按下弹开计数方式）[⚡] 仓库数据填补，如后期开源，前些版本中缺失的文件可在此次提交中找到。[/collapse][collapse status="true" title="v1.1.1"]发布日期：2023-09-04[💥] 修复了清除数据使用情况清除失败的问题[💥] 修复了总统计中进程统计缺少数据的问题[💥] 修复了筛选器清除不彻底的问题[🚩] 添加了数据库尺寸释放逻辑[🎈] 升级QT版本至6.52[/collapse][collapse status="true" title="v1.1.0"]发布日期：2023-07-05[💥] 修复了跨天数据异常[💥] 修复了开机自启动时没有隐藏窗口[🚩] 新增了应用统计部分筛选功能[🎈] 修改了部分提示词[/collapse][collapse status="true" title="v1.0.9"][scode type="green" size=""] 此版本修改了存储表结构，虽然存在增量更新结构，但是也建议重新初始化数据库。[/scode]发布日期：‎2023‎年‎6‎月‎28日[💥] 修复了插入数据时逻辑错误[🚩] 新增窗口键盘按键次数记录[🎈] 提高了查询和存储数据效率[/collapse][collapse status="true" title="v1.0.8"][scode type="green" size=""]强烈建议在这个版本之前安装的用户清除1下数据，因为之前的逻辑存在冗余的数据，占用磁盘空间和影响程序性能。[/scode]发布日期：‎2023‎年‎6‎月‎27‎日[💥] 修复了部分文字错误[💥] 修复了特殊情况下锁屏时记录错误的情况[💥] 修复了一些情况tooltip显示问题[💥] 修复了窗口弹窗标题版本遗留的U问题[💥] 修复了清除数据自定义日期范围，截图未按照规定清理的问题[💥] 修复了清除数据和初始化后窗口隐藏的逻辑问题[🚩] 新增导出tsv功能[🚩] 新增锁屏记录[🚩] 新增使用情况检索功能[🎈] 提高了用户体验[🎈] 优化了编码风格，便于后续迭代[/collapse][collapse status="true" title="v1.0.7"]发布日期：‎2023‎年‎6‎月‎26‎日[💥] 修复了总统计查询结果不准确的问题[💥] 修复了托盘事件和菜单中显示隐藏偶然出错问题[💥] 修复了查看历史键鼠统计时，按件统计部分热力图变为黑色[🚩] 新增屏幕截图删除功能[🚩] 新增主页面关闭按钮[🎈] 优化数据查询速度[🎈] 开机自动启动后自动最小化至托盘图标[🎈] 提高启动、切换页签时的用户体验[/collapse][collapse status="true" title="v1.0.6"]发布日期：‎2023‎年‎6‎月‎21‎日[💥] 修复了明亮主题下颜色不搭配的问题[💥] 修复了第一次启动时初始化完成后退出的问题[💥] 修复了应用统计计时器设计缺陷[🚩] 安装向导释放文件时结束已经运行着的程序[🚩] 安装向导采用自动化编码，自动化打包，提高了安全性[🎈] 修改了部分图标展示[/collapse][collapse status="true" title="v1.0.5"]发布日期：‎2023‎年‎6‎月‎21‎日[scode type="green" size=""]重量级更新[/scode][💥] 修复了空白处右键仍然显示的问题[💥] 修复了截图时间周期毫秒级错误[💥] 修复配置页面的钩子重启周期滑块最小值和预设值不匹配问题[💥] 修复应用统计类别无法排序问题[💥] 修复总统计部分类别无法显示问题[💥] 修复工程文件生成后丢失版本信息的问题[🚩] 新增时间轴查看大图按钮[🚩] 新增崩溃转储文件生成[🚩] 关于构造时间更加精确[🎈] 应用统计默认结束时间倒序展示[🎈] 图表部分tooltip优化[🎈] 区间统计起始日期默认前30天[🎈] 总统计汇总按钮提高用户体验[🎈] 提高启动时的用户体验[🎈] 简化了编译流程[🎈] 提高汇总页表格展示用户体验[🎈] 主页面的按钮添加tooltip[🎈] 主页面的键盘tooltip优化[🎈] 查看历史数据时，切换页签逻辑不再刷新数据[/collapse][collapse status="true" title="v1.0.4"]发布日期：‎2023‎年‎6‎月‎20日[💥] 修复了清除数据自定义区间起始结束校验问题[🚩] 新增桌面截图展示功能[🚩] 新增应用类别统计模块(类型指派，删除)[🚩] 新增删除某条使用记录功能[🚩] 新增复制某条使用记录功能[🎈] 优化截图展示的用户体验，保存缩略图[🎈] 优化了列表展示效果[🎈] 优化了列表展示效率[/collapse][collapse status="true" title="v1.0.3"]发布日期：‎2023‎年‎6‎月‎19‎日[💥] 修复了偶然在锁屏后应用统计会持续记录[💥] 修复了启动时检测更新设置失效问题[🎈] 优化了配置页面布局模式[🚩] 新增桌面截图功能[自动删除过期，设置][🚩] 新增了升级后数据库同步升级[/collapse][collapse status="true" title="v1.0.2"]发布日期：‎2023‎年‎6‎月‎14‎日[scode type="green" size=""]公开测试[/scode][💥] 修复了时间到第二天时键鼠记录累加的问题[🎈] 减小了打包后文件体积[/collapse][collapse status="true" title="v1.0.1"]发布日期：‎2023‎年‎6‎月‎12‎日[💥] 修复了开机自动启动时，文件路径定位问题，导致无法获取到许可证和数据库文件[💥] 修复了应用统计中explorer统计不准确的问题[💥] 缓释了查看图表中使用量情况时间精度导致大于60分钟的bug[💥] 修复了记录时时区导致时间错误的问题[🎈] 代码整洁性优化[🎈] 程序处理目录时更加优雅[🎈] 优化了日志输出时的数据类型，提高了程序运行效率[🚩] 新增了日志模块(UTF-8)[🚩] 新增了总统计页，区间选择日期统计[/collapse][collapse status="true" title="v1.0.0 β"]⚠：此版本为首发版，未对外进行发布，仅供测试。[🚩]鼠标点击监控[🚩]键盘按键监控[🚩]屏幕窗口标题侦听[🚩]数据持久化存储[🚩]托盘图标[🚩]统计图[/collapse]下载地址kmu-counter@1.1.5
引言QTableWidget 表头排序是根据字符串进行排序，如果这个列中只有数字，就变成了这样的了。解决方案重写QTableWidgetItem类class Item: public QTableWidgetItem { public: Item(QString str){ this->setText(str); } bool operator< (const QTableWidgetItem &other) const { return (this->text().toInt() < other.text().toInt()); } };调用时new Item(QString("%1").arg(staticData[row].getCount())));如果是字符串类型，就用原始的类，不要用重写的这个类，不然会排序失败的。
引言不加图标太丑了，其实添加图标还算是挺容易的。实现在pro文件中添加一行RC_ICONS = icon.ico 就可以了。如QT += core gui sql greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 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 \ mainwindow.cpp HEADERS += \ mainwindow.h \ FORMS += \ mainwindow.ui # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target RC_ICONS = icon.ico DISTFILES += RESOURCES += \ resource.qrc此时目录结构是这样的最终最终生成的文件是这样的。
引言在Qt Creator中构建项目后，直接打开编译后的程序，会提示如下窗口。找不到Qt*.dll，无法继续执行代码操作打开构建工具包，有些项目MinGW 可以编译，有些MSVC可以编译切换到构建目录，这个目录可以在下图所示部分找到。找到exe文件所在的路径执行命令windeployqt [exe文件]最终目录里会出现这么多文件简化打开exe文件，此时是可以正常打开的，不要关闭exe程序，全选这个目录里所有文件，删除，如果提示被占用无法删除的跳过，最终会剩下一部分文件，剩下的也是必要的文件了。如果还要精简，最好的方案是自己简化qt代码，自己打包qt。
引言最近做的这个小玩意儿我打算拦截关闭事件，并且提示，确定要关闭的询问，但是这上的图标始终都是这种难看的默认图标，怎么也没有改掉，反而询问的那个？可以自定义改掉，很头大。实践索性直接去掉图标吧，这样就省事儿了。msgBox.setWindowFlags(Qt::Drawer); // 去掉标题栏上的图标详细代码QMessageBox msgBox; msgBox.setWindowTitle(tr("退出")); msgBox.setWindowFlags(Qt::Drawer); // 去掉标题栏上的图标 msgBox.setIcon(QMessageBox::Question); msgBox.setText(tr("确定要退出吗？")); msgBox.setInformativeText(tr("退出后就不能监控按键数量了。")); QPushButton *ok = msgBox.addButton(tr(" 确定 "), QMessageBox::ActionRole); QPushButton *cancel = msgBox.addButton(tr(" 取消 "), QMessageBox::ActionRole); msgBox.setDefaultButton(ok); msgBox.setEscapeButton(cancel); msgBox.exec(); if (msgBox.clickedButton() == ok) { QApplication::exit(0); } else if (msgBox.clickedButton() == cancel) { return; }自定义显示图标msgBox.setIconPixmap(QPixmap(":/imgs/icon"));这种做法前提是需要提前把图标给放到资源文件中去。
引言对于C端程序，定时器的使用是比较普遍的，比如我编程启蒙语言易语言，如果说让他每秒进行一个操作，是很容易的。而js的话，setInterval也是可以很轻易的实现定时器功能，java语言通过TimerTask也是可以做到定时任务的功能。实现QT中的定时器也是很容易的就可以做到的，代码如下所示常规方式QTimer *timer = new QTimer(this); // 创建实例 connect(timer, &QTimer::timeout, this, &MainWindow::test); // 连接信号和槽 timer->start(5000); // 每5秒执行1次 timer->stop(); // 计时器停止如果是常规做法的话，需要创建函数，使其定时器调用那个函数。lambda方式创建QTimer * timer1 = new QTimer(this); timer1->start(1000); // 1000毫秒执行1次 connect(timer1,&QTimer::timeout,[=](){ // 业务部分 });[=]() 看起来像是提供this为参数的匿名函数，具体是什么意思有待剖析。截图