commit 5599bb19b8732b1808aa743c1812fbf2d44d1802 Author: nikola <2503865771@qq.com> Date: Fri Jul 21 21:46:24 2023 +0800 KDAv1.0 测试版本发布 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fab7372 --- /dev/null +++ b/.gitignore @@ -0,0 +1,73 @@ +# This file is used to ignore files which are generated +# ---------------------------------------------------------------------------- + +*~ +*.autosave +*.a +*.core +*.moc +*.o +*.obj +*.orig +*.rej +*.so +*.so.* +*_pch.h.cpp +*_resource.rc +*.qm +.#* +*.*# +core +!core/ +tags +.DS_Store +.directory +*.debug +Makefile* +*.prl +*.app +moc_*.cpp +ui_*.h +qrc_*.cpp +Thumbs.db +*.res +*.rc +/.qmake.cache +/.qmake.stash + +# qtcreator generated files +*.pro.user* + +# xemacs temporary files +*.flc + +# Vim temporary files +.*.swp + +# Visual Studio generated files +*.ib_pdb_index +*.idb +*.ilk +*.pdb +*.sln +*.suo +*.vcproj +*vcproj.*.*.user +*.ncb +*.sdf +*.opensdf +*.vcxproj +*vcxproj.* + +# MinGW generated files +*.Debug +*.Release + +# Python byte code +*.pyc + +# Binaries +# -------- +*.dll +*.exe + diff --git a/KDA_Logo.ico b/KDA_Logo.ico new file mode 100644 index 0000000..4956bb8 Binary files /dev/null and b/KDA_Logo.ico differ diff --git a/Keil5_disp_size_bar.c b/Keil5_disp_size_bar.c new file mode 100644 index 0000000..a62da20 --- /dev/null +++ b/Keil5_disp_size_bar.c @@ -0,0 +1,464 @@ +#if 0 + +#include +#include +#include +#include +#include +#include +#include +#include + +#define APP_NAME "Keil5_disp_size_bar V0.5" +typedef struct mcu_8051_size +{ + uint32_t iram_size; + uint32_t xram_size; + uint32_t irom_size; + uint32_t iram_max; + uint32_t xram_max; + uint32_t irom_max; +} mcu_8051_size_t; +mcu_8051_size_t mcu_8051 = {0}; + +void print_msg(const char *tag, const char *format, ...); +FILE *find_file_in_dir_by_name(const char *dir_name, const char *file_name); +int64_t file_sreach_string_get_pos(FILE *fp, char *sub_str, int seek, uint32_t offset); +void prtint_percentage_bar(char *label, uint8_t cnt, uint32_t val, uint32_t max); +uint32_t str_get_hex(char *str, char *str_hex); +void process_execution_region(FILE *fp_map); +float str_get_dec(char *str, char *str_dec); +uint8_t find_8051(void); +void find_project_size_define(void); + +uint32_t ram_max_from_porject = 0; +uint32_t rom_max_from_porject = 0; + +// argv[0] 是当前exe文件的路径 +// exe放在工程文件的同一目录下就可以获取到工程目录了 +int main2(int argc, char *argv[]) +{ + DIR *dir; + char *path = NULL; + FILE *fp_map; + // 打开当前目录 + int64_t pos = 0; + + if (find_8051()) + return; + + find_project_size_define(); + + print_msg(APP_NAME, "find map file start"); + fp_map = find_file_in_dir_by_name("./", ".map"); + + process_execution_region(fp_map); + + fclose(fp_map); + return 0; +} + +void print_msg(const char *tag, const char *format, ...) +{ + printf("[%s]: ", tag); + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); + printf("\n"); +} + +FILE *find_file_in_dir_by_name(const char *dir_name, const char *file_name) +{ + FILE *fp; + DIR *dir; + struct dirent *st; + struct stat sta; + + int ret = 0; + char tmp_name[1024] = {0}; + + if ((dir = opendir(dir_name)) == NULL) + { + printf("%s: Open dir error\n", APP_NAME); + return NULL; + } + + while ((st = readdir(dir)) != NULL) + { + strcpy(tmp_name, dir_name); + strcat(tmp_name, "/"); + strcat(tmp_name, st->d_name); // 新文件路径名 + + ret = stat(tmp_name, &sta); // 查看目录下文件属性 + + if (ret < 0) + { + print_msg(APP_NAME "Read stat failed for %s", tmp_name); + continue; + } + + if (S_ISDIR(sta.st_mode)) + { // 如果为目录文件 + if (strcmp("..", st->d_name) == 0 || strcmp(".", st->d_name) == 0) + { + continue; // 忽略当前目录和上一层目录 + } + else + { + fp = find_file_in_dir_by_name(tmp_name, file_name); // 递归读取 + if (fp) + { + closedir(dir); + return fp; + } + + + + } + } + else + { // 不为目录则打印文件路径名 + if (strstr(tmp_name, file_name)) + { + fp = fopen(tmp_name, "r+"); + if (!fp) + { + // print_msg(APP_NAME, "Failed to open file: %s", tmp_name); + return NULL; + } + else + { + print_msg(APP_NAME, "Found file: %s", tmp_name); + closedir(dir); + return fp; + } + } + } + } + + closedir(dir); + return NULL; +} + +int64_t file_sreach_string_get_pos(FILE *fp, char *sub_str, int seek, uint32_t offset) +{ + char str[1000]; + int64_t pos = 0; + fseek(fp, offset, seek); + + while (NULL != fgets(str, 1000, fp)) + { + + if (strstr(str, sub_str)) + { + + // printf("%s", str); + pos = ftell(fp) - strlen(str); + fseek(fp, pos, SEEK_SET); + return pos; + } + } + return -1; +} + +void prtint_percentage_bar(char *label, uint8_t cnt, uint32_t val, uint32_t max) +{ + uint8_t i; + printf("%5d KB %5s%u:|", (uint32_t)(max / 1024.0f), label, cnt); + + for (i = 0; i < 20; i++) + { + if (i < (uint8_t)((val / 1.0) / (max / 1.0) * 20)) + { + + printf("■"); + } + else + { + printf("_"); + } + } + printf("|%6.2f %% (%8.2f KB / %8.2f KB)", (val / 1.0) / (max / 1.0) * 100, val / 1024.0f, max / 1024.0f); + printf(" [%u B]\n", max - val); +} + +uint32_t str_get_hex(char *str, char *str_hex) +{ + + char *str_buf; + uint32_t hex; + + str_buf = strstr(str, str_hex); + if (str_buf == NULL) + return 0; + str_buf += strlen(str_hex); + sscanf(str_buf, "%x", &hex); + + // printf("%s:%#x\n", str_hex,hex); + + return hex; +} + +float str_get_dec(char *str, char *str_dec) +{ + + char *str_buf; + float dec; + + str_buf = strstr(str, str_dec); + if (str_buf == NULL) + return 0; + str_buf += strlen(str_dec); + sscanf(str_buf, "%f", &dec); + + // printf("%s:%#x\n", str_hex,hex); + + return dec; +} + +void process_execution_region(FILE *fp_map) +{ + + int64_t pos = 0; + char str[1000]; + char *ch_p = NULL; + uint32_t exec_base = 0, load_base = 0, size = 0, max = 0; + uint8_t ram_cnt = 0, flash_cnt = 0; + + uint8_t cnt = 0; + uint32_t ram_size[30]; + uint32_t flash_size[30]; + + uint32_t ram_max[30]; + uint32_t flash_max[30]; + + while (1) + { + + pos = file_sreach_string_get_pos(fp_map, "Execution Region", SEEK_SET, pos); + if (-1 == pos) + { + print_msg(APP_NAME, "map file read end\n"); + break; + } + + fseek(fp_map, pos, SEEK_SET); + fgets(str, 1000, fp_map); + + if (strstr(str, "RAM")) + { + + ram_size[ram_cnt] = str_get_hex(str, "Size: "); + pos += strstr(str, "Size: ") - str; + fseek(fp_map, pos, SEEK_SET); + + ram_max[ram_cnt] = str_get_hex(str, "Max: "); + if (ram_max[ram_cnt] > 100 * 1024 * 1024) + ram_max[ram_cnt] = ram_max_from_porject; + + pos += strstr(str, "Max: ") - str; + fseek(fp_map, pos, SEEK_SET); + if (ram_cnt < 30) + ram_cnt++; + // prtint_percentage_bar("ram",ram_cnt, size, max); + } + else if (strstr(str, "ER$$") ||strstr(str, "RW_")|| strstr(str, "ER_RW") || strstr(str, "ER_ZI")) + { + + ram_size[ram_cnt] = str_get_hex(str, "Size: "); + pos += strstr(str, "Size: ") - str; + fseek(fp_map, pos, SEEK_SET); + + ram_max[ram_cnt] = str_get_hex(str, "Max: "); + if (ram_max[ram_cnt] > 100 * 1024 * 1024) + ram_max[ram_cnt] = ram_max_from_porject; +print_msg(APP_NAME,"RAMMAX:%d\n",ram_max[ram_cnt]); + + pos += strstr(str, "Max: ") - str; + fseek(fp_map, pos, SEEK_SET); + if (ram_cnt < 30) + ram_cnt++; + // prtint_percentage_bar("ram",ram_cnt, size, max); + } + else + { + + flash_size[flash_cnt] = str_get_hex(str, "Size: "); + pos += strstr(str, "Size: ") - str; + fseek(fp_map, pos, SEEK_SET); + + flash_max[flash_cnt] = str_get_hex(str, "Max: "); + if (flash_max[flash_cnt] > 100 * 1024 * 1024) + flash_max[flash_cnt] = rom_max_from_porject; + + pos += strstr(str, "Max: ") - str; + fseek(fp_map, pos, SEEK_SET); + if (flash_cnt < 30) + flash_cnt++; + // prtint_percentage_bar("flash",flash_cnt, size, max); + } + } + + printf("ram:\n"); + for (cnt = 0; cnt < ram_cnt; cnt++) + { + prtint_percentage_bar("ram", cnt + 1, ram_size[cnt], ram_max[cnt]); + } + printf("flash:\n"); + for (cnt = 0; cnt < flash_cnt; cnt++) + { + prtint_percentage_bar("flash", cnt + 1, flash_size[cnt], flash_max[cnt]); + } + + printf(" \n"); +} + +uint8_t find_8051(void) +{ + FILE *fp_project=NULL; + FILE *fp_m51=NULL; + int64_t pos = 0; + char str[1000]; + + uint8_t cnt = 0; + + print_msg(APP_NAME, "find project satrt!"); + fp_project = find_file_in_dir_by_name("./", ".uvproj"); + if (fp_project == NULL) + { + print_msg(APP_NAME, "find project fail!"); + fp_project = find_file_in_dir_by_name("./", ".uvprojx"); + if (fp_project == NULL) + { + print_msg(APP_NAME, "find project fail!"); + return 0; + } + } + + + + while (1) + { + + pos = file_sreach_string_get_pos(fp_project, "", SEEK_SET, pos); + if (-1 == pos) + { + print_msg(APP_NAME, "found cup info fail\n"); + return 0; + } + + fseek(fp_project, pos - 8, SEEK_SET); + fgets(str, 1000, fp_project); + if (strstr(str, "IRAM(0-")) + { + + print_msg(APP_NAME, "cup is 8051\n"); + + mcu_8051.iram_max = str_get_hex(str, "IRAM(0-"); + + if(strstr(str, "XRAM(0-")) + mcu_8051.xram_max = str_get_hex(str, "XRAM(0-"); + else + mcu_8051.xram_max = mcu_8051.iram_max; + + mcu_8051.irom_max = str_get_hex(str, "IROM(0-"); + // printf("iram_max:%d,xram_max:%d,irom_max:%d\n",mcu_8051.iram_max,mcu_8051.xram_max,mcu_8051.irom_max); + fclose(fp_project); // 关闭文件 + fp_m51 = find_file_in_dir_by_name("./", ".m51"); + pos = file_sreach_string_get_pos(fp_m51, "Program Size:", SEEK_SET, pos); + fgets(str, 1000, fp_project); + mcu_8051.iram_size = str_get_dec(str, "data="); + + + + mcu_8051.irom_size = str_get_dec(str, "code="); + // printf("iram_size:%d,xram_size:%d,irom_size:%d\n",mcu_8051.iram_size,mcu_8051.xram_size,mcu_8051.irom_size); + + prtint_percentage_bar("flash", 1, mcu_8051.irom_size, mcu_8051.irom_max); + prtint_percentage_bar("iram", 1, mcu_8051.iram_size, mcu_8051.iram_max); + + if(strstr(str, "xdata=")) + { + mcu_8051.xram_size = str_get_dec(str, "xdata="); + prtint_percentage_bar("xram", 1, mcu_8051.xram_size, mcu_8051.xram_max); + } + + return 1; + + } + else + { + return 0; + } + } + + return 0; + + +} + +void find_project_size_define(void) +{ + + FILE *fp_project=NULL; + int64_t pos = 0; + char str[1000]; + char *ch_p = NULL; + + // print_msg(APP_NAME, "find project satrt!"); + fp_project = find_file_in_dir_by_name("./", ".uvproj"); + if (fp_project == NULL) + { + fp_project = find_file_in_dir_by_name("./", ".uvprojx"); + if (fp_project == NULL) + { + // print_msg(APP_NAME, "find project fail!"); + return ; + } + } + + + while (1) + { + + pos = file_sreach_string_get_pos(fp_project, "", SEEK_SET, pos); + if (-1 == pos) + { + print_msg(APP_NAME, "found cup info fail\n"); + return; + } + + fseek(fp_project, pos - 8, SEEK_SET); + fgets(str, 1000, fp_project); + if (ch_p = strstr(str, "IRAM(")) + { + if(strstr(ch_p, ",")) + { + ram_max_from_porject = str_get_hex(ch_p, ","); + ch_p = strstr(ch_p, ","); + ch_p++; + rom_max_from_porject = str_get_hex(ch_p, ","); + } + else if(strstr(ch_p, "-")) + { + ram_max_from_porject = str_get_hex(ch_p, "-"); + ch_p = strstr(ch_p, "-"); + ch_p++; + rom_max_from_porject = str_get_hex(ch_p, "-"); + } + // print_msg(APP_NAME,"IARM:%d,IROM:%d\n",ram_max_from_porject,rom_max_from_porject); + return; + } + else + { + return; + } + } + + + + fclose(fp_project); // 关闭文件 + +} +#endif diff --git a/R.qrc b/R.qrc new file mode 100644 index 0000000..d746cea --- /dev/null +++ b/R.qrc @@ -0,0 +1,6 @@ + + + KDA_Logo.ico + gitee.png + + diff --git a/find_path.cpp b/find_path.cpp new file mode 100644 index 0000000..5eee05f --- /dev/null +++ b/find_path.cpp @@ -0,0 +1,40 @@ +#include "find_path.h" +#include +#include +#include +#include +#include + +find_path::find_path() +{ + +} + QString find_path::find_file_path(const QString& dir_path,const QString& key_world) + { + QFileInfoList fileInfoList; + QString file_path=""; + QDir dir(dir_path); + foreach(QFileInfo info,dir.entryInfoList(QDir::NoDotAndDotDot | QDir::Dirs)){ + +// qDebug()<<"dir:"< +class find_path +{ +public: + find_path(); + static QString find_file_path(const QString& dir_path,const QString& key_world); + +}; + +#endif // FIND_PATH_H diff --git a/flatui.cpp b/flatui.cpp new file mode 100644 index 0000000..69c61dc --- /dev/null +++ b/flatui.cpp @@ -0,0 +1,170 @@ +#pragma execution_character_set("utf-8") + +#include "flatui.h" +#include "qpushbutton.h" +#include "qlineedit.h" +#include "qprogressbar.h" +#include "qslider.h" +#include "qradiobutton.h" +#include "qcheckbox.h" +#include "qscrollbar.h" +#include "qdebug.h" + +QString FlatUI::setPushButtonQss(QPushButton *btn, int radius, int padding, + const QString &normalColor, + const QString &normalTextColor, + const QString &hoverColor, + const QString &hoverTextColor, + const QString &pressedColor, + const QString &pressedTextColor) +{ + QStringList list; + list.append(QString("QPushButton{border-style:none;padding:%1px;border-radius:%2px;color:%3;background:%4;}") + .arg(padding).arg(radius).arg(normalTextColor).arg(normalColor)); + list.append(QString("QPushButton:hover{color:%1;background:%2;}") + .arg(hoverTextColor).arg(hoverColor)); + list.append(QString("QPushButton:pressed{color:%1;background:%2;}") + .arg(pressedTextColor).arg(pressedColor)); + + QString qss = list.join(""); + btn->setStyleSheet(qss); + return qss; +} + +QString FlatUI::setLineEditQss(QLineEdit *txt, int radius, int borderWidth, + const QString &normalColor, + const QString &focusColor) +{ + QStringList list; + list.append(QString("QLineEdit{border-style:none;padding:3px;border-radius:%1px;border:%2px solid %3;}") + .arg(radius).arg(borderWidth).arg(normalColor)); + list.append(QString("QLineEdit:focus{border:%1px solid %2;}") + .arg(borderWidth).arg(focusColor)); + + QString qss = list.join(""); + txt->setStyleSheet(qss); + return qss; +} + +QString FlatUI::setProgressQss(QProgressBar *bar, int barHeight, + int barRadius, int fontSize, + const QString &normalColor, + const QString &chunkColor) +{ + + QStringList list; + list.append(QString("QProgressBar{color:#FFFFFF;font:%1px;background:%2;max-height:%3px;border-radius:%4px;text-align:center;border:1px solid %2;}") + .arg(fontSize).arg(normalColor).arg(barHeight).arg(barRadius)); + list.append(QString("QProgressBar:chunk{border-radius:%2px;background-color:%1;}") + .arg(chunkColor).arg(barRadius)); + + QString qss = list.join(""); + bar->setStyleSheet(qss); + return qss; +} + +QString FlatUI::setSliderQss(QSlider *slider, int sliderHeight, + const QString &normalColor, + const QString &grooveColor, + const QString &handleBorderColor, + const QString &handleColor) +{ + int sliderRadius = sliderHeight / 2; + int handleWidth = (sliderHeight * 3) / 2 + (sliderHeight / 5); + int handleRadius = handleWidth / 2; + int handleOffset = handleRadius / 2; + + QStringList list; + list.append(QString("QSlider::horizontal{min-height:%1px;}").arg(sliderHeight * 2)); + list.append(QString("QSlider::groove:horizontal{background:%1;height:%2px;border-radius:%3px;}") + .arg(normalColor).arg(sliderHeight).arg(sliderRadius)); + list.append(QString("QSlider::add-page:horizontal{background:%1;height:%2px;border-radius:%3px;}") + .arg(normalColor).arg(sliderHeight).arg(sliderRadius)); + list.append(QString("QSlider::sub-page:horizontal{background:%1;height:%2px;border-radius:%3px;}") + .arg(grooveColor).arg(sliderHeight).arg(sliderRadius)); + list.append(QString("QSlider::handle:horizontal{width:%3px;margin-top:-%4px;margin-bottom:-%4px;border-radius:%5px;" + "background:qradialgradient(spread:pad,cx:0.5,cy:0.5,radius:0.5,fx:0.5,fy:0.5,stop:0.6 %1,stop:0.8 %2);}") + .arg(handleColor).arg(handleBorderColor).arg(handleWidth).arg(handleOffset).arg(handleRadius)); + + //偏移一个像素 + handleWidth = handleWidth + 1; + list.append(QString("QSlider::vertical{min-width:%1px;}").arg(sliderHeight * 2)); + list.append(QString("QSlider::groove:vertical{background:%1;width:%2px;border-radius:%3px;}") + .arg(normalColor).arg(sliderHeight).arg(sliderRadius)); + list.append(QString("QSlider::add-page:vertical{background:%1;width:%2px;border-radius:%3px;}") + .arg(grooveColor).arg(sliderHeight).arg(sliderRadius)); + list.append(QString("QSlider::sub-page:vertical{background:%1;width:%2px;border-radius:%3px;}") + .arg(normalColor).arg(sliderHeight).arg(sliderRadius)); + list.append(QString("QSlider::handle:vertical{height:%3px;margin-left:-%4px;margin-right:-%4px;border-radius:%5px;" + "background:qradialgradient(spread:pad,cx:0.5,cy:0.5,radius:0.5,fx:0.5,fy:0.5,stop:0.6 %1,stop:0.8 %2);}") + .arg(handleColor).arg(handleBorderColor).arg(handleWidth).arg(handleOffset).arg(handleRadius)); + + QString qss = list.join(""); + slider->setStyleSheet(qss); + return qss; +} + +QString FlatUI::setRadioButtonQss(QRadioButton *rbtn, int indicatorRadius, + const QString &normalColor, + const QString &checkColor) +{ + int indicatorWidth = indicatorRadius * 2; + + QStringList list; + list.append(QString("QRadioButton::indicator{border-radius:%1px;width:%2px;height:%2px;}") + .arg(indicatorRadius).arg(indicatorWidth)); + list.append(QString("QRadioButton::indicator::unchecked{background:qradialgradient(spread:pad,cx:0.5,cy:0.5,radius:0.5,fx:0.5,fy:0.5," + "stop:0.6 #FFFFFF,stop:0.7 %1);}").arg(normalColor)); + list.append(QString("QRadioButton::indicator::checked{background:qradialgradient(spread:pad,cx:0.5,cy:0.5,radius:0.5,fx:0.5,fy:0.5," + "stop:0 %1,stop:0.3 %1,stop:0.4 #FFFFFF,stop:0.6 #FFFFFF,stop:0.7 %1);}").arg(checkColor)); + + QString qss = list.join(""); + rbtn->setStyleSheet(qss); + return qss; +} + +QString FlatUI::setScrollBarQss(QWidget *scroll, int radius, int min, int max, + const QString &bgColor, + const QString &handleNormalColor, + const QString &handleHoverColor, + const QString &handlePressedColor) +{ + //滚动条离背景间隔 + int padding = 0; + + QStringList list; + + //handle:指示器,滚动条拉动部分 add-page:滚动条拉动时增加的部分 sub-page:滚动条拉动时减少的部分 add-line:递增按钮 sub-line:递减按钮 + + //横向滚动条部分 + list.append(QString("QScrollBar:horizontal{background:%1;padding:%2px;border-radius:%3px;min-height:%4px;max-height:%4px;}") + .arg(bgColor).arg(padding).arg(radius).arg(max)); + list.append(QString("QScrollBar::handle:horizontal{background:%1;min-width:%2px;border-radius:%3px;}") + .arg(handleNormalColor).arg(min).arg(radius)); + list.append(QString("QScrollBar::handle:horizontal:hover{background:%1;}") + .arg(handleHoverColor)); + list.append(QString("QScrollBar::handle:horizontal:pressed{background:%1;}") + .arg(handlePressedColor)); + list.append(QString("QScrollBar::add-page:horizontal{background:none;}")); + list.append(QString("QScrollBar::sub-page:horizontal{background:none;}")); + list.append(QString("QScrollBar::add-line:horizontal{background:none;}")); + list.append(QString("QScrollBar::sub-line:horizontal{background:none;}")); + + //纵向滚动条部分 + list.append(QString("QScrollBar:vertical{background:%1;padding:%2px;border-radius:%3px;min-width:%4px;max-width:%4px;}") + .arg(bgColor).arg(padding).arg(radius).arg(max)); + list.append(QString("QScrollBar::handle:vertical{background:%1;min-height:%2px;border-radius:%3px;}") + .arg(handleNormalColor).arg(min).arg(radius)); + list.append(QString("QScrollBar::handle:vertical:hover{background:%1;}") + .arg(handleHoverColor)); + list.append(QString("QScrollBar::handle:vertical:pressed{background:%1;}") + .arg(handlePressedColor)); + list.append(QString("QScrollBar::add-page:vertical{background:none;}")); + list.append(QString("QScrollBar::sub-page:vertical{background:none;}")); + list.append(QString("QScrollBar::add-line:vertical{background:none;}")); + list.append(QString("QScrollBar::sub-line:vertical{background:none;}")); + + QString qss = list.join(""); + scroll->setStyleSheet(qss); + return qss; +} diff --git a/flatui.h b/flatui.h new file mode 100644 index 0000000..bfcb64c --- /dev/null +++ b/flatui.h @@ -0,0 +1,85 @@ +#ifndef FLATUI_H +#define FLATUI_H + +/** + * FlatUI辅助类 作者:feiyangqingyun(QQ:517216493) 2016-12-16 + * 1. 按钮样式设置。 + * 2. 文本框样式设置。 + * 3. 进度条样式。 + * 4. 滑块条样式。 + * 5. 单选框样式。 + * 6. 滚动条样式。 + * 7. 可自由设置对象的高度宽度大小等。 + * 8. 自带默认参数值。 + */ + +#include + +class QPushButton; +class QLineEdit; +class QProgressBar; +class QSlider; +class QRadioButton; +class QCheckBox; +class QScrollBar; + +#ifdef quc +class Q_DECL_EXPORT FlatUI +#else +class FlatUI +#endif + +{ +public: + //设置按钮样式 + static QString setPushButtonQss(QPushButton *btn, //按钮对象 + int radius = 5, //圆角半径 + int padding = 8, //间距 + const QString &normalColor = "#34495E", //正常颜色 + const QString &normalTextColor = "#FFFFFF", //文字颜色 + const QString &hoverColor = "#4E6D8C", //悬停颜色 + const QString &hoverTextColor = "#F0F0F0", //悬停文字颜色 + const QString &pressedColor = "#2D3E50", //按下颜色 + const QString &pressedTextColor = "#B8C6D1"); //按下文字颜色 + + //设置文本框样式 + static QString setLineEditQss(QLineEdit *txt, //文本框对象 + int radius = 3, //圆角半径 + int borderWidth = 2, //边框大小 + const QString &normalColor = "#DCE4EC", //正常颜色 + const QString &focusColor = "#34495E"); //选中颜色 + + //设置进度条样式 + static QString setProgressQss(QProgressBar *bar, + int barHeight = 8, //进度条高度 + int barRadius = 5, //进度条半径 + int fontSize = 12, //文字字号 + const QString &normalColor = "#E8EDF2", //正常颜色 + const QString &chunkColor = "#E74C3C"); //进度颜色 + + //设置滑块条样式 + static QString setSliderQss(QSlider *slider, //滑动条对象 + int sliderHeight = 8, //滑动条高度 + const QString &normalColor = "#E8EDF2", //正常颜色 + const QString &grooveColor = "#1ABC9C", //滑块颜色 + const QString &handleBorderColor = "#1ABC9C", //指示器边框颜色 + const QString &handleColor = "#FFFFFF"); //指示器颜色 + + //设置单选框样式 + static QString setRadioButtonQss(QRadioButton *rbtn, //单选框对象 + int indicatorRadius = 8, //指示器圆角角度 + const QString &normalColor = "#D7DBDE", //正常颜色 + const QString &checkColor = "#34495E"); //选中颜色 + + //设置滚动条样式 + static QString setScrollBarQss(QWidget *scroll, //滚动条对象 + int radius = 6, //圆角角度 + int min = 120, //指示器最小长度 + int max = 12, //滚动条最大长度 + const QString &bgColor = "#606060", //背景色 + const QString &handleNormalColor = "#34495E", //指示器正常颜色 + const QString &handleHoverColor = "#1ABC9C", //指示器悬停颜色 + const QString &handlePressedColor = "#E74C3C"); //指示器按下颜色 +}; + +#endif // FLATUI_H diff --git a/framelesscore/framelesscore.pri b/framelesscore/framelesscore.pri new file mode 100644 index 0000000..3662227 --- /dev/null +++ b/framelesscore/framelesscore.pri @@ -0,0 +1,9 @@ +HEADERS += \ + $$PWD/framelessdialog.h \ + $$PWD/framelessmainwindow.h \ + $$PWD/framelesswidget.h + +SOURCES += \ + $$PWD/framelessdialog.cpp \ + $$PWD/framelessmainwindow.cpp \ + $$PWD/framelesswidget.cpp diff --git a/framelesscore/framelessdialog.cpp b/framelesscore/framelessdialog.cpp new file mode 100644 index 0000000..9d8f875 --- /dev/null +++ b/framelesscore/framelessdialog.cpp @@ -0,0 +1,377 @@ +#include "framelessdialog.h" +#include "qdatetime.h" +#include "qevent.h" +#include "qdebug.h" + +#ifdef Q_OS_WIN +#include "windows.h" +#include "windowsx.h" +#pragma comment (lib,"user32.lib") +#endif + +#define TIMEMS qPrintable(QTime::currentTime().toString("HH:mm:ss zzz")) + +FramelessDialog::FramelessDialog(QWidget *parent) : QDialog(parent) +{ + padding = 8; + moveEnable = true; + resizeEnable = true; + + mousePressed = false; + mousePoint = QPoint(0, 0); + mouseRect = QRect(0, 0, 0, 0); + + for (int i = 0; i < 8; ++i) { + pressedArea << false; + pressedRect << QRect(0, 0, 0, 0); + } + + isMin = false; + flags = this->windowFlags(); + titleBar = 0; + + //设置背景透明 官方在5.3以后才彻底修复 WA_TranslucentBackground+FramelessWindowHint 并存不绘制的bug +#if (QT_VERSION >= QT_VERSION_CHECK(5,3,0)) + this->setAttribute(Qt::WA_TranslucentBackground); +#endif + //设置无边框属性 + this->setWindowFlags(flags | Qt::FramelessWindowHint); + //安装事件过滤器识别拖动 + this->installEventFilter(this); + + //设置属性产生win窗体效果,移动到边缘半屏或者最大化等 + //设置以后会产生标题栏需要在下面拦截消息重新去掉 +#ifdef Q_OS_WIN + HWND hwnd = (HWND)this->winId(); + DWORD style = ::GetWindowLong(hwnd, GWL_STYLE); + ::SetWindowLong(hwnd, GWL_STYLE, style | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CAPTION); +#endif +} + +void FramelessDialog::showEvent(QShowEvent *event) +{ + //解决有时候窗体重新显示的时候假死不刷新的bug + setAttribute(Qt::WA_Mapped); + QDialog::showEvent(event); +} + +void FramelessDialog::doWindowStateChange(QEvent *event) +{ + //非最大化才能移动和拖动大小 + if (windowState() == Qt::WindowNoState) { + moveEnable = true; + resizeEnable = true; + } else { + moveEnable = false; + resizeEnable = false; + } + + //发出最大化最小化等改变事件,以便界面上更改对应的信息比如右上角图标和文字 + emit windowStateChange(!moveEnable); + + //解决mac系统上无边框最小化失效的bug +#ifdef Q_OS_MACOS + if (windowState() & Qt::WindowMinimized) { + isMin = true; + } else { + if (isMin) { + //设置无边框属性 + this->setWindowFlags(flags | Qt::FramelessWindowHint); + this->setVisible(true); + isMin = false; + } + } +#endif +} + +void FramelessDialog::doResizeEvent(QEvent *event) +{ + //非win系统的无边框拉伸,win系统上已经采用了nativeEvent来处理拉伸 + //为何不统一用计算的方式因为在win上用这个方式往左拉伸会发抖妹的 +#ifndef Q_OS_WIN + if (event->type() == QEvent::Resize) { + //重新计算八个描点的区域,描点区域的作用还有就是计算鼠标坐标是否在某一个区域内 + int width = this->width(); + int height = this->height(); + + //左侧描点区域 + pressedRect[0] = QRect(0, padding, padding, height - padding * 2); + //右侧描点区域 + pressedRect[1] = QRect(width - padding, padding, padding, height - padding * 2); + //上侧描点区域 + pressedRect[2] = QRect(padding, 0, width - padding * 2, padding); + //下侧描点区域 + pressedRect[3] = QRect(padding, height - padding, width - padding * 2, padding); + + //左上角描点区域 + pressedRect[4] = QRect(0, 0, padding, padding); + //右上角描点区域 + pressedRect[5] = QRect(width - padding, 0, padding, padding); + //左下角描点区域 + pressedRect[6] = QRect(0, height - padding, padding, padding); + //右下角描点区域 + pressedRect[7] = QRect(width - padding, height - padding, padding, padding); + } else if (event->type() == QEvent::HoverMove) { + //设置对应鼠标形状,这个必须放在这里而不是下面,因为可以在鼠标没有按下的时候识别 + QHoverEvent *hoverEvent = (QHoverEvent *)event; + QPoint point = hoverEvent->pos(); + if (resizeEnable) { + if (pressedRect.at(0).contains(point)) { + this->setCursor(Qt::SizeHorCursor); + } else if (pressedRect.at(1).contains(point)) { + this->setCursor(Qt::SizeHorCursor); + } else if (pressedRect.at(2).contains(point)) { + this->setCursor(Qt::SizeVerCursor); + } else if (pressedRect.at(3).contains(point)) { + this->setCursor(Qt::SizeVerCursor); + } else if (pressedRect.at(4).contains(point)) { + this->setCursor(Qt::SizeFDiagCursor); + } else if (pressedRect.at(5).contains(point)) { + this->setCursor(Qt::SizeBDiagCursor); + } else if (pressedRect.at(6).contains(point)) { + this->setCursor(Qt::SizeBDiagCursor); + } else if (pressedRect.at(7).contains(point)) { + this->setCursor(Qt::SizeFDiagCursor); + } else { + this->setCursor(Qt::ArrowCursor); + } + } + + //根据当前鼠标位置,计算XY轴移动了多少 + int offsetX = point.x() - mousePoint.x(); + int offsetY = point.y() - mousePoint.y(); + + //根据按下处的位置判断是否是移动控件还是拉伸控件 + if (moveEnable && mousePressed) { + this->move(this->x() + offsetX, this->y() + offsetY); + } + + if (resizeEnable) { + int rectX = mouseRect.x(); + int rectY = mouseRect.y(); + int rectW = mouseRect.width(); + int rectH = mouseRect.height(); + + if (pressedArea.at(0)) { + int resizeW = this->width() - offsetX; + if (this->minimumWidth() <= resizeW) { + this->setGeometry(this->x() + offsetX, rectY, resizeW, rectH); + } + } else if (pressedArea.at(1)) { + this->setGeometry(rectX, rectY, rectW + offsetX, rectH); + } else if (pressedArea.at(2)) { + int resizeH = this->height() - offsetY; + if (this->minimumHeight() <= resizeH) { + this->setGeometry(rectX, this->y() + offsetY, rectW, resizeH); + } + } else if (pressedArea.at(3)) { + this->setGeometry(rectX, rectY, rectW, rectH + offsetY); + } else if (pressedArea.at(4)) { + int resizeW = this->width() - offsetX; + int resizeH = this->height() - offsetY; + if (this->minimumWidth() <= resizeW) { + this->setGeometry(this->x() + offsetX, this->y(), resizeW, resizeH); + } + if (this->minimumHeight() <= resizeH) { + this->setGeometry(this->x(), this->y() + offsetY, resizeW, resizeH); + } + } else if (pressedArea.at(5)) { + int resizeW = rectW + offsetX; + int resizeH = this->height() - offsetY; + if (this->minimumHeight() <= resizeH) { + this->setGeometry(this->x(), this->y() + offsetY, resizeW, resizeH); + } + } else if (pressedArea.at(6)) { + int resizeW = this->width() - offsetX; + int resizeH = rectH + offsetY; + if (this->minimumWidth() <= resizeW) { + this->setGeometry(this->x() + offsetX, this->y(), resizeW, resizeH); + } + if (this->minimumHeight() <= resizeH) { + this->setGeometry(this->x(), this->y(), resizeW, resizeH); + } + } else if (pressedArea.at(7)) { + int resizeW = rectW + offsetX; + int resizeH = rectH + offsetY; + this->setGeometry(this->x(), this->y(), resizeW, resizeH); + } + } + } else if (event->type() == QEvent::MouseButtonPress) { + //记住鼠标按下的坐标+窗体区域 + QMouseEvent *mouseEvent = (QMouseEvent *)event; + mousePoint = mouseEvent->pos(); + mouseRect = this->geometry(); + + //判断按下的手柄的区域位置 + if (pressedRect.at(0).contains(mousePoint)) { + pressedArea[0] = true; + } else if (pressedRect.at(1).contains(mousePoint)) { + pressedArea[1] = true; + } else if (pressedRect.at(2).contains(mousePoint)) { + pressedArea[2] = true; + } else if (pressedRect.at(3).contains(mousePoint)) { + pressedArea[3] = true; + } else if (pressedRect.at(4).contains(mousePoint)) { + pressedArea[4] = true; + } else if (pressedRect.at(5).contains(mousePoint)) { + pressedArea[5] = true; + } else if (pressedRect.at(6).contains(mousePoint)) { + pressedArea[6] = true; + } else if (pressedRect.at(7).contains(mousePoint)) { + pressedArea[7] = true; + } else { + mousePressed = true; + } + } else if (event->type() == QEvent::MouseMove) { + //改成用HoverMove识别 + } else if (event->type() == QEvent::MouseButtonRelease) { + //恢复所有 + this->setCursor(Qt::ArrowCursor); + mousePressed = false; + for (int i = 0; i < 8; ++i) { + pressedArea[i] = false; + } + } +#endif +} + +bool FramelessDialog::eventFilter(QObject *watched, QEvent *event) +{ + if (watched == this) { + if (event->type() == QEvent::WindowStateChange) { + doWindowStateChange(event); + } else { + doResizeEvent(event); + } + } else if (watched == titleBar) { + //双击标题栏发出双击信号给主界面 + //下面的 *result = HTCAPTION; 标志位也会自动识别双击标题栏 +#ifndef Q_OS_WIN + if (event->type() == QEvent::MouseButtonDblClick) { + emit titleDblClick(); + } else if (event->type() == QEvent::NonClientAreaMouseButtonDblClick) { + emit titleDblClick(); + } +#endif + } + + return QDialog::eventFilter(watched, event); +} + +#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) +bool FramelessDialog::nativeEvent(const QByteArray &eventType, void *message, qintptr *result) +#else +bool FramelessDialog::nativeEvent(const QByteArray &eventType, void *message, long *result) +#endif +{ + if (eventType == "windows_generic_MSG") { +#ifdef Q_OS_WIN + MSG *msg = static_cast(message); + //qDebug() << TIMEMS << "nativeEvent" << msg->wParam << msg->message; + + //不同的消息类型和参数进行不同的处理 + if (msg->message == WM_NCCALCSIZE) { + *result = 0; + return true; + } else if (msg->message == WM_SYSKEYDOWN) { + //屏蔽alt键按下 + } else if (msg->message == WM_SYSKEYUP) { + //屏蔽alt键松开 + } else if (msg->message == WM_NCHITTEST) { + //计算鼠标对应的屏幕坐标 + //这里最开始用的 LOWORD HIWORD 在多屏幕的时候会有问题 + //官方说明在这里 https://docs.microsoft.com/zh-cn/windows/win32/inputdev/wm-nchittest + long x = GET_X_LPARAM(msg->lParam); + long y = GET_Y_LPARAM(msg->lParam); + QPoint pos = mapFromGlobal(QPoint(x, y)); + + //判断当前鼠标位置在哪个区域 + bool left = pos.x() < padding; + bool right = pos.x() > width() - padding; + bool top = pos.y() < padding; + bool bottom = pos.y() > height() - padding; + + //鼠标移动到四个角,这个消息是当鼠标移动或者有鼠标键按下时候发出的 + *result = 0; + if (resizeEnable) { + if (left && top) { + *result = HTTOPLEFT; + } else if (left && bottom) { + *result = HTBOTTOMLEFT; + } else if (right && top) { + *result = HTTOPRIGHT; + } else if (right && bottom) { + *result = HTBOTTOMRIGHT; + } else if (left) { + *result = HTLEFT; + } else if (right) { + *result = HTRIGHT; + } else if (top) { + *result = HTTOP; + } else if (bottom) { + *result = HTBOTTOM; + } + } + + //先处理掉拉伸 + if (0 != *result) { + return true; + } + + //识别标题栏拖动产生半屏全屏效果 + if (titleBar && titleBar->rect().contains(pos)) { + QWidget *child = titleBar->childAt(pos); + if (!child) { + *result = HTCAPTION; + return true; + } + } + } else if (msg->wParam == PBT_APMSUSPEND && msg->message == WM_POWERBROADCAST) { + //系统休眠的时候自动最小化可以规避程序可能出现的问题 + this->showMinimized(); + } else if (msg->wParam == PBT_APMRESUMEAUTOMATIC) { + //休眠唤醒后自动打开 + this->showNormal(); + } +#endif + } else if (eventType == "NSEvent") { +#ifdef Q_OS_MACOS +#endif + } else if (eventType == "xcb_generic_event_t") { +#ifdef Q_OS_LINUX +#endif + } + return false; +} + +#if (QT_VERSION < QT_VERSION_CHECK(5,0,0)) +#ifdef Q_OS_WIN +bool FramelessDialog::winEvent(MSG *message, long *result) +{ + return nativeEvent("windows_generic_MSG", message, result); +} +#endif +#endif + +void FramelessDialog::setPadding(int padding) +{ + this->padding = padding; +} + +void FramelessDialog::setMoveEnable(bool moveEnable) +{ + this->moveEnable = moveEnable; +} + +void FramelessDialog::setResizeEnable(bool resizeEnable) +{ + this->resizeEnable = resizeEnable; +} + +void FramelessDialog::setTitleBar(QWidget *titleBar) +{ + this->titleBar = titleBar; + this->titleBar->installEventFilter(this); +} + + diff --git a/framelesscore/framelessdialog.h b/framelesscore/framelessdialog.h new file mode 100644 index 0000000..fd6d5fb --- /dev/null +++ b/framelesscore/framelessdialog.h @@ -0,0 +1,96 @@ +#ifndef FRAMELESSDIALOG_H +#define FRAMELESSDIALOG_H + +/** + * 无边框窗体类 作者:feiyangqingyun(QQ:517216493) 2021-07-27 + * 1. 同时支持Qt4-Qt6,亲测Qt4.7到Qt6.2。 + * 2. 同时支持mingw、msvc、gcc等。 + * 3. 同时支持windows、linux、mac。 + * 4. 同时支持QMainWindow、QWidget、QDialog。 + * 5. 使用方法极其简单,只需要将继承类修改即可。 + * 6. 自动识别双击标题栏响应。 + * 7. 无边框拉伸在windows下不抖动。 + * 8. 在windows下具有移动到边缘半屏、移动到顶部全屏特性。 + * 9. 解决mac系统上无边框最小化最大化失效的bug。 + * 10. 解决系统休眠后再次启动程序懵逼的bug。 + * 11. 解决有时候窗体重新显示的时候假死不刷新的bug。 + * 12. 轻量级,1个代码文件,核心代码行数不到300行。 + * 13. 注释详细,示例完美,非常适合阅读和学习。 + * 14. 开源开箱即用,保证任意Qt版本可正常编译运行,无需任何调整。 + */ + +#include + +#ifdef quc +class Q_DECL_EXPORT FramelessDialog : public QDialog +#else +class FramelessDialog : public QDialog +#endif + +{ + Q_OBJECT +public: + explicit FramelessDialog(QWidget *parent = 0); + +protected: + //窗体显示的时候触发 + void showEvent(QShowEvent *event); + + //事件过滤器识别拖动拉伸等 + void doWindowStateChange(QEvent *event); + void doResizeEvent(QEvent *event); + bool eventFilter(QObject *watched, QEvent *event); + + //拦截系统事件用于修复系统休眠后唤醒程序的bug +#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) + bool nativeEvent(const QByteArray &eventType, void *message, qintptr *result); +#else + bool nativeEvent(const QByteArray &eventType, void *message, long *result); +#endif + + //Qt4的写法 +#if (QT_VERSION < QT_VERSION_CHECK(5,0,0)) +#ifdef Q_OS_WIN + bool winEvent(MSG *message, long *result); +#endif +#endif + +private: + //边距+可移动+可拉伸 + int padding; + bool moveEnable; + bool resizeEnable; + + //标题栏控件 + QWidget *titleBar; + + //鼠标是否按下+按下坐标+按下时窗体区域 + bool mousePressed; + QPoint mousePoint; + QRect mouseRect; + + //鼠标是否按下某个区域+按下区域的大小 + //依次为 左侧+右侧+上侧+下侧+左上侧+右上侧+左下侧+右下侧 + QList pressedArea; + QList pressedRect; + + //记录是否最小化 + bool isMin; + //存储窗体默认的属性 + Qt::WindowFlags flags; + +public Q_SLOTS: + //设置边距+可拖动+可拉伸 + void setPadding(int padding); + void setMoveEnable(bool moveEnable); + void setResizeEnable(bool resizeEnable); + + //设置标题栏控件 + void setTitleBar(QWidget *titleBar); + +Q_SIGNALS: + void titleDblClick(); + void windowStateChange(bool max); +}; + +#endif // FRAMELESSDIALOG_H diff --git a/framelesscore/framelessmainwindow.cpp b/framelesscore/framelessmainwindow.cpp new file mode 100644 index 0000000..2cc91cf --- /dev/null +++ b/framelesscore/framelessmainwindow.cpp @@ -0,0 +1,375 @@ +#include "framelessmainwindow.h" +#include "qdatetime.h" +#include "qevent.h" +#include "qdebug.h" + +#ifdef Q_OS_WIN +#include "windows.h" +#include "windowsx.h" +#pragma comment (lib,"user32.lib") +#endif + +#define TIMEMS qPrintable(QTime::currentTime().toString("HH:mm:ss zzz")) + +FramelessMainWindow::FramelessMainWindow(QWidget *parent) : QMainWindow(parent) +{ + padding = 8; + moveEnable = true; + resizeEnable = true; + + mousePressed = false; + mousePoint = QPoint(0, 0); + mouseRect = QRect(0, 0, 0, 0); + + for (int i = 0; i < 8; ++i) { + pressedArea << false; + pressedRect << QRect(0, 0, 0, 0); + } + + isMin = false; + flags = this->windowFlags(); + titleBar = 0; + + //设置背景透明 官方在5.3以后才彻底修复 WA_TranslucentBackground+FramelessWindowHint 并存不绘制的bug +#if (QT_VERSION >= QT_VERSION_CHECK(5,3,0)) + this->setAttribute(Qt::WA_TranslucentBackground); +#endif + //设置无边框属性 + this->setWindowFlags(flags | Qt::FramelessWindowHint); + //安装事件过滤器识别拖动 + this->installEventFilter(this); + + //设置属性产生win窗体效果,移动到边缘半屏或者最大化等 + //设置以后会产生标题栏,需要在下面拦截消息WM_NCCALCSIZE重新去掉 +#ifdef Q_OS_WIN + HWND hwnd = (HWND)this->winId(); + DWORD style = ::GetWindowLong(hwnd, GWL_STYLE); + ::SetWindowLong(hwnd, GWL_STYLE, style | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CAPTION); +#endif +} + +void FramelessMainWindow::showEvent(QShowEvent *event) +{ + //解决有时候窗体重新显示的时候假死不刷新的bug + setAttribute(Qt::WA_Mapped); + QMainWindow::showEvent(event); +} + +void FramelessMainWindow::doWindowStateChange(QEvent *event) +{ + //非最大化才能移动和拖动大小 + if (windowState() == Qt::WindowNoState) { + moveEnable = true; + resizeEnable = true; + } else { + moveEnable = false; + resizeEnable = false; + } + + //发出最大化最小化等改变事件,以便界面上更改对应的信息比如右上角图标和文字 + emit windowStateChange(!moveEnable); + + //解决mac系统上无边框最小化失效的bug +#ifdef Q_OS_MACOS + if (windowState() & Qt::WindowMinimized) { + isMin = true; + } else { + if (isMin) { + //设置无边框属性 + this->setWindowFlags(flags | Qt::FramelessWindowHint); + this->setVisible(true); + isMin = false; + } + } +#endif +} + +void FramelessMainWindow::doResizeEvent(QEvent *event) +{ + //非win系统的无边框拉伸,win系统上已经采用了nativeEvent来处理拉伸 + //为何不统一用计算的方式因为在win上用这个方式往左拉伸会发抖妹的 +#ifndef Q_OS_WIN + if (event->type() == QEvent::Resize) { + //重新计算八个描点的区域,描点区域的作用还有就是计算鼠标坐标是否在某一个区域内 + int width = this->width(); + int height = this->height(); + + //左侧描点区域 + pressedRect[0] = QRect(0, padding, padding, height - padding * 2); + //右侧描点区域 + pressedRect[1] = QRect(width - padding, padding, padding, height - padding * 2); + //上侧描点区域 + pressedRect[2] = QRect(padding, 0, width - padding * 2, padding); + //下侧描点区域 + pressedRect[3] = QRect(padding, height - padding, width - padding * 2, padding); + + //左上角描点区域 + pressedRect[4] = QRect(0, 0, padding, padding); + //右上角描点区域 + pressedRect[5] = QRect(width - padding, 0, padding, padding); + //左下角描点区域 + pressedRect[6] = QRect(0, height - padding, padding, padding); + //右下角描点区域 + pressedRect[7] = QRect(width - padding, height - padding, padding, padding); + } else if (event->type() == QEvent::HoverMove) { + //设置对应鼠标形状,这个必须放在这里而不是下面,因为可以在鼠标没有按下的时候识别 + QHoverEvent *hoverEvent = (QHoverEvent *)event; + QPoint point = hoverEvent->pos(); + if (resizeEnable) { + if (pressedRect.at(0).contains(point)) { + this->setCursor(Qt::SizeHorCursor); + } else if (pressedRect.at(1).contains(point)) { + this->setCursor(Qt::SizeHorCursor); + } else if (pressedRect.at(2).contains(point)) { + this->setCursor(Qt::SizeVerCursor); + } else if (pressedRect.at(3).contains(point)) { + this->setCursor(Qt::SizeVerCursor); + } else if (pressedRect.at(4).contains(point)) { + this->setCursor(Qt::SizeFDiagCursor); + } else if (pressedRect.at(5).contains(point)) { + this->setCursor(Qt::SizeBDiagCursor); + } else if (pressedRect.at(6).contains(point)) { + this->setCursor(Qt::SizeBDiagCursor); + } else if (pressedRect.at(7).contains(point)) { + this->setCursor(Qt::SizeFDiagCursor); + } else { + this->setCursor(Qt::ArrowCursor); + } + } + + //根据当前鼠标位置,计算XY轴移动了多少 + int offsetX = point.x() - mousePoint.x(); + int offsetY = point.y() - mousePoint.y(); + + //根据按下处的位置判断是否是移动控件还是拉伸控件 + if (moveEnable && mousePressed) { + this->move(this->x() + offsetX, this->y() + offsetY); + } + + if (resizeEnable) { + int rectX = mouseRect.x(); + int rectY = mouseRect.y(); + int rectW = mouseRect.width(); + int rectH = mouseRect.height(); + + if (pressedArea.at(0)) { + int resizeW = this->width() - offsetX; + if (this->minimumWidth() <= resizeW) { + this->setGeometry(this->x() + offsetX, rectY, resizeW, rectH); + } + } else if (pressedArea.at(1)) { + this->setGeometry(rectX, rectY, rectW + offsetX, rectH); + } else if (pressedArea.at(2)) { + int resizeH = this->height() - offsetY; + if (this->minimumHeight() <= resizeH) { + this->setGeometry(rectX, this->y() + offsetY, rectW, resizeH); + } + } else if (pressedArea.at(3)) { + this->setGeometry(rectX, rectY, rectW, rectH + offsetY); + } else if (pressedArea.at(4)) { + int resizeW = this->width() - offsetX; + int resizeH = this->height() - offsetY; + if (this->minimumWidth() <= resizeW) { + this->setGeometry(this->x() + offsetX, this->y(), resizeW, resizeH); + } + if (this->minimumHeight() <= resizeH) { + this->setGeometry(this->x(), this->y() + offsetY, resizeW, resizeH); + } + } else if (pressedArea.at(5)) { + int resizeW = rectW + offsetX; + int resizeH = this->height() - offsetY; + if (this->minimumHeight() <= resizeH) { + this->setGeometry(this->x(), this->y() + offsetY, resizeW, resizeH); + } + } else if (pressedArea.at(6)) { + int resizeW = this->width() - offsetX; + int resizeH = rectH + offsetY; + if (this->minimumWidth() <= resizeW) { + this->setGeometry(this->x() + offsetX, this->y(), resizeW, resizeH); + } + if (this->minimumHeight() <= resizeH) { + this->setGeometry(this->x(), this->y(), resizeW, resizeH); + } + } else if (pressedArea.at(7)) { + int resizeW = rectW + offsetX; + int resizeH = rectH + offsetY; + this->setGeometry(this->x(), this->y(), resizeW, resizeH); + } + } + } else if (event->type() == QEvent::MouseButtonPress) { + //记住鼠标按下的坐标+窗体区域 + QMouseEvent *mouseEvent = (QMouseEvent *)event; + mousePoint = mouseEvent->pos(); + mouseRect = this->geometry(); + + //判断按下的手柄的区域位置 + if (pressedRect.at(0).contains(mousePoint)) { + pressedArea[0] = true; + } else if (pressedRect.at(1).contains(mousePoint)) { + pressedArea[1] = true; + } else if (pressedRect.at(2).contains(mousePoint)) { + pressedArea[2] = true; + } else if (pressedRect.at(3).contains(mousePoint)) { + pressedArea[3] = true; + } else if (pressedRect.at(4).contains(mousePoint)) { + pressedArea[4] = true; + } else if (pressedRect.at(5).contains(mousePoint)) { + pressedArea[5] = true; + } else if (pressedRect.at(6).contains(mousePoint)) { + pressedArea[6] = true; + } else if (pressedRect.at(7).contains(mousePoint)) { + pressedArea[7] = true; + } else { + mousePressed = true; + } + } else if (event->type() == QEvent::MouseMove) { + //改成用HoverMove识别 + } else if (event->type() == QEvent::MouseButtonRelease) { + //恢复所有 + this->setCursor(Qt::ArrowCursor); + mousePressed = false; + for (int i = 0; i < 8; ++i) { + pressedArea[i] = false; + } + } +#endif +} + +bool FramelessMainWindow::eventFilter(QObject *watched, QEvent *event) +{ + if (watched == this) { + if (event->type() == QEvent::WindowStateChange) { + doWindowStateChange(event); + } else { + doResizeEvent(event); + } + } else if (watched == titleBar) { + //双击标题栏发出双击信号给主界面 + //下面的 *result = HTCAPTION; 标志位也会自动识别双击标题栏 +#ifndef Q_OS_WIN + if (event->type() == QEvent::MouseButtonDblClick) { + emit titleDblClick(); + } else if (event->type() == QEvent::NonClientAreaMouseButtonDblClick) { + emit titleDblClick(); + } +#endif + } + + return QMainWindow::eventFilter(watched, event); +} + +#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) +bool FramelessMainWindow::nativeEvent(const QByteArray &eventType, void *message, qintptr *result) +#else +bool FramelessMainWindow::nativeEvent(const QByteArray &eventType, void *message, long *result) +#endif +{ + if (eventType == "windows_generic_MSG") { +#ifdef Q_OS_WIN + MSG *msg = static_cast(message); + //qDebug() << TIMEMS << "nativeEvent" << msg->wParam << msg->message; + + //不同的消息类型和参数进行不同的处理 + if (msg->message == WM_NCCALCSIZE) { + *result = 0; + return true; + } else if (msg->message == WM_SYSKEYDOWN) { + //屏蔽alt键按下 + } else if (msg->message == WM_SYSKEYUP) { + //屏蔽alt键松开 + } else if (msg->message == WM_NCHITTEST) { + //计算鼠标对应的屏幕坐标 + //这里最开始用的 LOWORD HIWORD 在多屏幕的时候会有问题 + //官方说明在这里 https://docs.microsoft.com/zh-cn/windows/win32/inputdev/wm-nchittest + long x = GET_X_LPARAM(msg->lParam); + long y = GET_Y_LPARAM(msg->lParam); + QPoint pos = mapFromGlobal(QPoint(x, y)); + + //判断当前鼠标位置在哪个区域 + bool left = pos.x() < padding; + bool right = pos.x() > width() - padding; + bool top = pos.y() < padding; + bool bottom = pos.y() > height() - padding; + + //鼠标移动到四个角,这个消息是当鼠标移动或者有鼠标键按下时候发出的 + *result = 0; + if (resizeEnable) { + if (left && top) { + *result = HTTOPLEFT; + } else if (left && bottom) { + *result = HTBOTTOMLEFT; + } else if (right && top) { + *result = HTTOPRIGHT; + } else if (right && bottom) { + *result = HTBOTTOMRIGHT; + } else if (left) { + *result = HTLEFT; + } else if (right) { + *result = HTRIGHT; + } else if (top) { + *result = HTTOP; + } else if (bottom) { + *result = HTBOTTOM; + } + } + + //先处理掉拉伸 + if (0 != *result) { + return true; + } + + //识别标题栏拖动产生半屏全屏效果 + if (titleBar && titleBar->rect().contains(pos)) { + QWidget *child = titleBar->childAt(pos); + if (!child) { + *result = HTCAPTION; + return true; + } + } + } else if (msg->wParam == PBT_APMSUSPEND && msg->message == WM_POWERBROADCAST) { + //系统休眠的时候自动最小化可以规避程序可能出现的问题 + this->showMinimized(); + } else if (msg->wParam == PBT_APMRESUMEAUTOMATIC) { + //休眠唤醒后自动打开 + this->showNormal(); + } +#endif + } else if (eventType == "NSEvent") { +#ifdef Q_OS_MACOS +#endif + } else if (eventType == "xcb_generic_event_t") { +#ifdef Q_OS_LINUX +#endif + } + return false; +} + +#if (QT_VERSION < QT_VERSION_CHECK(5,0,0)) +#ifdef Q_OS_WIN +bool FramelessMainWindow::winEvent(MSG *message, long *result) +{ + return nativeEvent("windows_generic_MSG", message, result); +} +#endif +#endif + +void FramelessMainWindow::setPadding(int padding) +{ + this->padding = padding; +} + +void FramelessMainWindow::setMoveEnable(bool moveEnable) +{ + this->moveEnable = moveEnable; +} + +void FramelessMainWindow::setResizeEnable(bool resizeEnable) +{ + this->resizeEnable = resizeEnable; +} + +void FramelessMainWindow::setTitleBar(QWidget *titleBar) +{ + this->titleBar = titleBar; + this->titleBar->installEventFilter(this); +} diff --git a/framelesscore/framelessmainwindow.h b/framelesscore/framelessmainwindow.h new file mode 100644 index 0000000..a069705 --- /dev/null +++ b/framelesscore/framelessmainwindow.h @@ -0,0 +1,96 @@ +#ifndef FRAMELESSMAINWINDOW_H +#define FRAMELESSMAINWINDOW_H + +/** + * 无边框窗体类 作者:feiyangqingyun(QQ:517216493) 2021-07-27 + * 1. 同时支持Qt4-Qt6,亲测Qt4.7到Qt6.2。 + * 2. 同时支持mingw、msvc、gcc等。 + * 3. 同时支持windows、linux、mac。 + * 4. 同时支持QMainWindow、QWidget、QDialog。 + * 5. 使用方法极其简单,只需要将继承类修改即可。 + * 6. 自动识别双击标题栏响应。 + * 7. 无边框拉伸在windows下不抖动。 + * 8. 在windows下具有移动到边缘半屏、移动到顶部全屏特性。 + * 9. 解决mac系统上无边框最小化最大化失效的bug。 + * 10. 解决系统休眠后再次启动程序懵逼的bug。 + * 11. 解决有时候窗体重新显示的时候假死不刷新的bug。 + * 12. 轻量级,1个代码文件,核心代码行数不到300行。 + * 13. 注释详细,示例完美,非常适合阅读和学习。 + * 14. 开源开箱即用,保证任意Qt版本可正常编译运行,无需任何调整。 + */ + +#include + +#ifdef quc +class Q_DECL_EXPORT FramelessMainWindow : public QMainWindow +#else +class FramelessMainWindow : public QMainWindow +#endif + +{ + Q_OBJECT +public: + explicit FramelessMainWindow(QWidget *parent = 0); + +protected: + //窗体显示的时候触发 + void showEvent(QShowEvent *event); + + //事件过滤器识别拖动拉伸等 + void doWindowStateChange(QEvent *event); + void doResizeEvent(QEvent *event); + bool eventFilter(QObject *watched, QEvent *event); + + //拦截系统事件用于修复系统休眠后唤醒程序的bug +#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) + bool nativeEvent(const QByteArray &eventType, void *message, qintptr *result); +#else + bool nativeEvent(const QByteArray &eventType, void *message, long *result); +#endif + + //Qt4的写法 +#if (QT_VERSION < QT_VERSION_CHECK(5,0,0)) +#ifdef Q_OS_WIN + bool winEvent(MSG *message, long *result); +#endif +#endif + +private: + //边距+可移动+可拉伸 + int padding; + bool moveEnable; + bool resizeEnable; + + //标题栏控件 + QWidget *titleBar; + + //鼠标是否按下+按下坐标+按下时窗体区域 + bool mousePressed; + QPoint mousePoint; + QRect mouseRect; + + //鼠标是否按下某个区域+按下区域的大小 + //依次为 左侧+右侧+上侧+下侧+左上侧+右上侧+左下侧+右下侧 + QList pressedArea; + QList pressedRect; + + //记录是否最小化 + bool isMin; + //存储窗体默认的属性 + Qt::WindowFlags flags; + +public Q_SLOTS: + //设置边距+可拖动+可拉伸 + void setPadding(int padding); + void setMoveEnable(bool moveEnable); + void setResizeEnable(bool resizeEnable); + + //设置标题栏控件 + void setTitleBar(QWidget *titleBar); + +Q_SIGNALS: + void titleDblClick(); + void windowStateChange(bool max); +}; + +#endif // FRAMELESSMAINWINDOW_H diff --git a/framelesscore/framelesswidget.cpp b/framelesscore/framelesswidget.cpp new file mode 100644 index 0000000..8382588 --- /dev/null +++ b/framelesscore/framelesswidget.cpp @@ -0,0 +1,377 @@ +#include "framelesswidget.h" +#include "qdatetime.h" +#include "qevent.h" +#include "qdebug.h" + +#ifdef Q_OS_WIN +#include "windows.h" +#include "windowsx.h" +#pragma comment (lib,"user32.lib") +#endif + +#define TIMEMS qPrintable(QTime::currentTime().toString("HH:mm:ss zzz")) + +FramelessWidget::FramelessWidget(QWidget *parent) : QWidget(parent) +{ + padding = 8; + moveEnable = true; + resizeEnable = true; + + mousePressed = false; + mousePoint = QPoint(0, 0); + mouseRect = QRect(0, 0, 0, 0); + + for (int i = 0; i < 8; ++i) { + pressedArea << false; + pressedRect << QRect(0, 0, 0, 0); + } + + isMin = false; + flags = this->windowFlags(); + titleBar = 0; + + //设置背景透明 官方在5.3以后才彻底修复 WA_TranslucentBackground+FramelessWindowHint 并存不绘制的bug +#if (QT_VERSION >= QT_VERSION_CHECK(5,3,0)) + this->setAttribute(Qt::WA_TranslucentBackground); +#endif + //设置无边框属性 + this->setWindowFlags(flags | Qt::FramelessWindowHint); + //安装事件过滤器识别拖动 + this->installEventFilter(this); + + //设置属性产生win窗体效果,移动到边缘半屏或者最大化等 + //设置以后会产生标题栏需要在下面拦截消息重新去掉 +#ifdef Q_OS_WIN + HWND hwnd = (HWND)this->winId(); + DWORD style = ::GetWindowLong(hwnd, GWL_STYLE); + ::SetWindowLong(hwnd, GWL_STYLE, style | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CAPTION); +#endif +} + +void FramelessWidget::showEvent(QShowEvent *event) +{ + //解决有时候窗体重新显示的时候假死不刷新的bug + setAttribute(Qt::WA_Mapped); + QWidget::showEvent(event); +} + +void FramelessWidget::doWindowStateChange(QEvent *event) +{ + //非最大化才能移动和拖动大小 + if (windowState() == Qt::WindowNoState) { + moveEnable = true; + resizeEnable = true; + } else { + moveEnable = false; + resizeEnable = false; + } + + //发出最大化最小化等改变事件,以便界面上更改对应的信息比如右上角图标和文字 + emit windowStateChange(!moveEnable); + + //解决mac系统上无边框最小化失效的bug +#ifdef Q_OS_MACOS + if (windowState() & Qt::WindowMinimized) { + isMin = true; + } else { + if (isMin) { + //设置无边框属性 + this->setWindowFlags(flags | Qt::FramelessWindowHint); + this->setVisible(true); + isMin = false; + } + } +#endif +} + +void FramelessWidget::doResizeEvent(QEvent *event) +{ + //非win系统的无边框拉伸,win系统上已经采用了nativeEvent来处理拉伸 + //为何不统一用计算的方式因为在win上用这个方式往左拉伸会发抖妹的 +#ifndef Q_OS_WIN + if (event->type() == QEvent::Resize) { + //重新计算八个描点的区域,描点区域的作用还有就是计算鼠标坐标是否在某一个区域内 + int width = this->width(); + int height = this->height(); + + //左侧描点区域 + pressedRect[0] = QRect(0, padding, padding, height - padding * 2); + //右侧描点区域 + pressedRect[1] = QRect(width - padding, padding, padding, height - padding * 2); + //上侧描点区域 + pressedRect[2] = QRect(padding, 0, width - padding * 2, padding); + //下侧描点区域 + pressedRect[3] = QRect(padding, height - padding, width - padding * 2, padding); + + //左上角描点区域 + pressedRect[4] = QRect(0, 0, padding, padding); + //右上角描点区域 + pressedRect[5] = QRect(width - padding, 0, padding, padding); + //左下角描点区域 + pressedRect[6] = QRect(0, height - padding, padding, padding); + //右下角描点区域 + pressedRect[7] = QRect(width - padding, height - padding, padding, padding); + } else if (event->type() == QEvent::HoverMove) { + //设置对应鼠标形状,这个必须放在这里而不是下面,因为可以在鼠标没有按下的时候识别 + QHoverEvent *hoverEvent = (QHoverEvent *)event; + QPoint point = hoverEvent->pos(); + if (resizeEnable) { + if (pressedRect.at(0).contains(point)) { + this->setCursor(Qt::SizeHorCursor); + } else if (pressedRect.at(1).contains(point)) { + this->setCursor(Qt::SizeHorCursor); + } else if (pressedRect.at(2).contains(point)) { + this->setCursor(Qt::SizeVerCursor); + } else if (pressedRect.at(3).contains(point)) { + this->setCursor(Qt::SizeVerCursor); + } else if (pressedRect.at(4).contains(point)) { + this->setCursor(Qt::SizeFDiagCursor); + } else if (pressedRect.at(5).contains(point)) { + this->setCursor(Qt::SizeBDiagCursor); + } else if (pressedRect.at(6).contains(point)) { + this->setCursor(Qt::SizeBDiagCursor); + } else if (pressedRect.at(7).contains(point)) { + this->setCursor(Qt::SizeFDiagCursor); + } else { + this->setCursor(Qt::ArrowCursor); + } + } + + //根据当前鼠标位置,计算XY轴移动了多少 + int offsetX = point.x() - mousePoint.x(); + int offsetY = point.y() - mousePoint.y(); + + //根据按下处的位置判断是否是移动控件还是拉伸控件 + if (moveEnable && mousePressed) { + this->move(this->x() + offsetX, this->y() + offsetY); + } + + if (resizeEnable) { + int rectX = mouseRect.x(); + int rectY = mouseRect.y(); + int rectW = mouseRect.width(); + int rectH = mouseRect.height(); + + if (pressedArea.at(0)) { + int resizeW = this->width() - offsetX; + if (this->minimumWidth() <= resizeW) { + this->setGeometry(this->x() + offsetX, rectY, resizeW, rectH); + } + } else if (pressedArea.at(1)) { + this->setGeometry(rectX, rectY, rectW + offsetX, rectH); + } else if (pressedArea.at(2)) { + int resizeH = this->height() - offsetY; + if (this->minimumHeight() <= resizeH) { + this->setGeometry(rectX, this->y() + offsetY, rectW, resizeH); + } + } else if (pressedArea.at(3)) { + this->setGeometry(rectX, rectY, rectW, rectH + offsetY); + } else if (pressedArea.at(4)) { + int resizeW = this->width() - offsetX; + int resizeH = this->height() - offsetY; + if (this->minimumWidth() <= resizeW) { + this->setGeometry(this->x() + offsetX, this->y(), resizeW, resizeH); + } + if (this->minimumHeight() <= resizeH) { + this->setGeometry(this->x(), this->y() + offsetY, resizeW, resizeH); + } + } else if (pressedArea.at(5)) { + int resizeW = rectW + offsetX; + int resizeH = this->height() - offsetY; + if (this->minimumHeight() <= resizeH) { + this->setGeometry(this->x(), this->y() + offsetY, resizeW, resizeH); + } + } else if (pressedArea.at(6)) { + int resizeW = this->width() - offsetX; + int resizeH = rectH + offsetY; + if (this->minimumWidth() <= resizeW) { + this->setGeometry(this->x() + offsetX, this->y(), resizeW, resizeH); + } + if (this->minimumHeight() <= resizeH) { + this->setGeometry(this->x(), this->y(), resizeW, resizeH); + } + } else if (pressedArea.at(7)) { + int resizeW = rectW + offsetX; + int resizeH = rectH + offsetY; + this->setGeometry(this->x(), this->y(), resizeW, resizeH); + } + } + } else if (event->type() == QEvent::MouseButtonPress) { + //记住鼠标按下的坐标+窗体区域 + QMouseEvent *mouseEvent = (QMouseEvent *)event; + mousePoint = mouseEvent->pos(); + mouseRect = this->geometry(); + + //判断按下的手柄的区域位置 + if (pressedRect.at(0).contains(mousePoint)) { + pressedArea[0] = true; + } else if (pressedRect.at(1).contains(mousePoint)) { + pressedArea[1] = true; + } else if (pressedRect.at(2).contains(mousePoint)) { + pressedArea[2] = true; + } else if (pressedRect.at(3).contains(mousePoint)) { + pressedArea[3] = true; + } else if (pressedRect.at(4).contains(mousePoint)) { + pressedArea[4] = true; + } else if (pressedRect.at(5).contains(mousePoint)) { + pressedArea[5] = true; + } else if (pressedRect.at(6).contains(mousePoint)) { + pressedArea[6] = true; + } else if (pressedRect.at(7).contains(mousePoint)) { + pressedArea[7] = true; + } else { + mousePressed = true; + } + } else if (event->type() == QEvent::MouseMove) { + //改成用HoverMove识别 + } else if (event->type() == QEvent::MouseButtonRelease) { + //恢复所有 + this->setCursor(Qt::ArrowCursor); + mousePressed = false; + for (int i = 0; i < 8; ++i) { + pressedArea[i] = false; + } + } +#endif +} + +bool FramelessWidget::eventFilter(QObject *watched, QEvent *event) +{ + if (watched == this) { + if (event->type() == QEvent::WindowStateChange) { + doWindowStateChange(event); + } else { + doResizeEvent(event); + } + } else if (watched == titleBar) { + //双击标题栏发出双击信号给主界面 + //下面的 *result = HTCAPTION; 标志位也会自动识别双击标题栏 +#ifndef Q_OS_WIN + if (event->type() == QEvent::MouseButtonDblClick) { + emit titleDblClick(); + } else if (event->type() == QEvent::NonClientAreaMouseButtonDblClick) { + emit titleDblClick(); + } +#endif + } + + return QWidget::eventFilter(watched, event); +} + +#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) +bool FramelessWidget::nativeEvent(const QByteArray &eventType, void *message, qintptr *result) +#else +bool FramelessWidget::nativeEvent(const QByteArray &eventType, void *message, long *result) +#endif +{ + if (eventType == "windows_generic_MSG") { +#ifdef Q_OS_WIN + MSG *msg = static_cast(message); + //qDebug() << TIMEMS << "nativeEvent" << msg->wParam << msg->message; + + //不同的消息类型和参数进行不同的处理 + if (msg->message == WM_NCCALCSIZE) { + *result = 0; + return true; + } else if (msg->message == WM_SYSKEYDOWN) { + //屏蔽alt键按下 + } else if (msg->message == WM_SYSKEYUP) { + //屏蔽alt键松开 + } else if (msg->message == WM_NCHITTEST) { + //计算鼠标对应的屏幕坐标 + //这里最开始用的 LOWORD HIWORD 在多屏幕的时候会有问题 + //官方说明在这里 https://docs.microsoft.com/zh-cn/windows/win32/inputdev/wm-nchittest + long x = GET_X_LPARAM(msg->lParam); + long y = GET_Y_LPARAM(msg->lParam); + QPoint pos = mapFromGlobal(QPoint(x, y)); + + //判断当前鼠标位置在哪个区域 + bool left = pos.x() < padding; + bool right = pos.x() > width() - padding; + bool top = pos.y() < padding; + bool bottom = pos.y() > height() - padding; + + //鼠标移动到四个角,这个消息是当鼠标移动或者有鼠标键按下时候发出的 + *result = 0; + if (resizeEnable) { + if (left && top) { + *result = HTTOPLEFT; + } else if (left && bottom) { + *result = HTBOTTOMLEFT; + } else if (right && top) { + *result = HTTOPRIGHT; + } else if (right && bottom) { + *result = HTBOTTOMRIGHT; + } else if (left) { + *result = HTLEFT; + } else if (right) { + *result = HTRIGHT; + } else if (top) { + *result = HTTOP; + } else if (bottom) { + *result = HTBOTTOM; + } + } + + //先处理掉拉伸 + if (0 != *result) { + return true; + } + + //识别标题栏拖动产生半屏全屏效果 + if (titleBar && titleBar->rect().contains(pos)) { + QWidget *child = titleBar->childAt(pos); + if (!child) { + *result = HTCAPTION; + return true; + } + } + } else if (msg->wParam == PBT_APMSUSPEND && msg->message == WM_POWERBROADCAST) { + //系统休眠的时候自动最小化可以规避程序可能出现的问题 + this->showMinimized(); + } else if (msg->wParam == PBT_APMRESUMEAUTOMATIC) { + //休眠唤醒后自动打开 + this->showNormal(); + } +#endif + } else if (eventType == "NSEvent") { +#ifdef Q_OS_MACOS +#endif + } else if (eventType == "xcb_generic_event_t") { +#ifdef Q_OS_LINUX +#endif + } + return false; +} + +#if (QT_VERSION < QT_VERSION_CHECK(5,0,0)) +#ifdef Q_OS_WIN +bool FramelessWidget::winEvent(MSG *message, long *result) +{ + return nativeEvent("windows_generic_MSG", message, result); +} +#endif +#endif + +void FramelessWidget::setPadding(int padding) +{ + this->padding = padding; +} + +void FramelessWidget::setMoveEnable(bool moveEnable) +{ + this->moveEnable = moveEnable; +} + +void FramelessWidget::setResizeEnable(bool resizeEnable) +{ + this->resizeEnable = resizeEnable; +} + +void FramelessWidget::setTitleBar(QWidget *titleBar) +{ + this->titleBar = titleBar; + this->titleBar->installEventFilter(this); +} + + diff --git a/framelesscore/framelesswidget.h b/framelesscore/framelesswidget.h new file mode 100644 index 0000000..6494fc9 --- /dev/null +++ b/framelesscore/framelesswidget.h @@ -0,0 +1,96 @@ +#ifndef FRAMELESSWIDGET_H +#define FRAMELESSWIDGET_H + +/** + * 无边框窗体类 作者:feiyangqingyun(QQ:517216493) 2021-07-27 + * 1. 同时支持Qt4-Qt6,亲测Qt4.7到Qt6.2。 + * 2. 同时支持mingw、msvc、gcc等。 + * 3. 同时支持windows、linux、mac。 + * 4. 同时支持QMainWindow、QWidget、QDialog。 + * 5. 使用方法极其简单,只需要将继承类修改即可。 + * 6. 自动识别双击标题栏响应。 + * 7. 无边框拉伸在windows下不抖动。 + * 8. 在windows下具有移动到边缘半屏、移动到顶部全屏特性。 + * 9. 解决mac系统上无边框最小化最大化失效的bug。 + * 10. 解决系统休眠后再次启动程序懵逼的bug。 + * 11. 解决有时候窗体重新显示的时候假死不刷新的bug。 + * 12. 轻量级,1个代码文件,核心代码行数不到300行。 + * 13. 注释详细,示例完美,非常适合阅读和学习。 + * 14. 开源开箱即用,保证任意Qt版本可正常编译运行,无需任何调整。 + */ + +#include + +#ifdef quc +class Q_DECL_EXPORT FramelessWidget : public QWidget +#else +class FramelessWidget : public QWidget +#endif + +{ + Q_OBJECT +public: + explicit FramelessWidget(QWidget *parent = 0); + +protected: + //窗体显示的时候触发 + void showEvent(QShowEvent *event); + + //事件过滤器识别拖动拉伸等 + void doWindowStateChange(QEvent *event); + void doResizeEvent(QEvent *event); + bool eventFilter(QObject *watched, QEvent *event); + + //拦截系统事件用于修复系统休眠后唤醒程序的bug +#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) + bool nativeEvent(const QByteArray &eventType, void *message, qintptr *result); +#else + bool nativeEvent(const QByteArray &eventType, void *message, long *result); +#endif + + //Qt4的写法 +#if (QT_VERSION < QT_VERSION_CHECK(5,0,0)) +#ifdef Q_OS_WIN + bool winEvent(MSG *message, long *result); +#endif +#endif + +private: + //边距+可移动+可拉伸 + int padding; + bool moveEnable; + bool resizeEnable; + + //标题栏控件 + QWidget *titleBar; + + //鼠标是否按下+按下坐标+按下时窗体区域 + bool mousePressed; + QPoint mousePoint; + QRect mouseRect; + + //鼠标是否按下某个区域+按下区域的大小 + //依次为 左侧+右侧+上侧+下侧+左上侧+右上侧+左下侧+右下侧 + QList pressedArea; + QList pressedRect; + + //记录是否最小化 + bool isMin; + //存储窗体默认的属性 + Qt::WindowFlags flags; + +public Q_SLOTS: + //设置边距+可拖动+可拉伸 + void setPadding(int padding); + void setMoveEnable(bool moveEnable); + void setResizeEnable(bool resizeEnable); + + //设置标题栏控件 + void setTitleBar(QWidget *titleBar); + +Q_SIGNALS: + void titleDblClick(); + void windowStateChange(bool max); +}; + +#endif // FRAMELESSWIDGET_H diff --git a/gitee.png b/gitee.png new file mode 100644 index 0000000..13a1d65 Binary files /dev/null and b/gitee.png differ diff --git a/keil_development_assistant.pro b/keil_development_assistant.pro new file mode 100644 index 0000000..3115be0 --- /dev/null +++ b/keil_development_assistant.pro @@ -0,0 +1,66 @@ +QT += core gui xml charts printsupport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + + +include($$PWD/framelesscore/framelesscore.pri) + + +INCLUDEPATH +=$$PWD/framelesscore/ + +SOURCES += \ + find_path.cpp \ + flatui.cpp \ + main.cpp \ + mainwindow.cpp \ + only_run_by_file.cpp \ + parse_keil_project.cpp \ + parse_m51_from_keil.cpp \ + parse_map_from_keil.cpp \ + use_percentage_bar.cpp + +HEADERS += \ + find_path.h \ + flatui.h \ + mainwindow.h \ + only_run_by_file.h \ + parse_keil_project.h \ + parse_m51_from_keil.h \ + parse_map_from_keil.h \ + use_percentage_bar.h + +FORMS += \ + mainwindow.ui \ + use_percentage_bar.ui + +TRANSLATIONS += \ + keil_development_assistant_zh_CN.ts + +RC_FILE =ico.rc + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +DISTFILES += \ + KDA_Logo.ico \ + ico.rc \ + qcustomplot/GPL.txt \ + qcustomplot/changelog.txt + +RESOURCES += \ + R.qrc diff --git a/keil_development_assistant_zh_CN.ts b/keil_development_assistant_zh_CN.ts new file mode 100644 index 0000000..3aaca77 --- /dev/null +++ b/keil_development_assistant_zh_CN.ts @@ -0,0 +1,3 @@ + + + diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..3fc40a2 --- /dev/null +++ b/main.cpp @@ -0,0 +1,58 @@ +#include "mainwindow.h" +#include + +#include +#include + +MainWindow* main_window=nullptr; + +#include "only_run_by_file.h" +void onAppExit() +{ + // 删除 run 文件 + QFile::remove("run"); +} + +QString project_path; +QString map_path; +bool only_printf=false; + +int main(int argc, char *argv[]) +{ + +// for(int i=0;i3) + { + project_path=argv[1]; + map_path=argv[2]; + only_printf=argv[3]; + + }else if(argc>2) + { + project_path=map_path=argv[1]; + only_printf=argv[2]; + } + if(argc>1) + { + project_path="./"; + map_path="./"; + only_printf=argv[1]; + } + + + QApplication a(argc, argv); + + + only_run_by_file programController; + QObject::connect(&programController, &only_run_by_file::runFileDeleted, &a, &QCoreApplication::quit); + // 注册程序退出的处理函数 + QObject::connect(&a, &QCoreApplication::aboutToQuit, onAppExit); + + MainWindow w; + + if(!only_printf) w.show(); + + return a.exec(); +} diff --git a/mainwindow.cpp b/mainwindow.cpp new file mode 100644 index 0000000..c2933d1 --- /dev/null +++ b/mainwindow.cpp @@ -0,0 +1,764 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" + +#include +#include "use_percentage_bar.h" + +#include +#include "flatui.h" +#include +#include +extern MainWindow* main_window; +#pragma execution_character_set("utf-8") + + + + +MainWindow::MainWindow(QWidget *parent) : FramelessMainWindow(parent), ui(new Ui::MainWindow) +{ + ui->setupUi(this); + this->initForm(); +} + +MainWindow::~MainWindow() +{ + delete cpu; + delete map; + delete ram_chart; + delete flash_chart; + delete ui; +} + +void MainWindow::initForm() +{ + //设置标题栏控件 + ui->labTitle->setText("一个极客开源::keil开发助手"); + this->setWindowTitle(ui->labTitle->text()); + this->setTitleBar(ui->labTitle); + + //关联信号 + connect(this, SIGNAL(titleDblClick()), this, SLOT(titleDblClick())); + connect(this, SIGNAL(windowStateChange(bool)), this, SLOT(windowStateChange(bool))); + + //设置样式表 + QStringList list; + list << "#titleBar{background:#BBBBBB;}"; + list << "#titleBar{border-top-left-radius:8px;border-top-right-radius:8px;}"; + list << "#widgetMain{border:2px solid #BBBBBB;background:#FFFFFF;}"; + //list << "#widgetMain{border-bottom-left-radius:8px;border-bottom-right-radius:8px;}"; + this->setStyleSheet(list.join("")); + FlatUI::setScrollBarQss(ui->ram_scrollArea->verticalScrollBar(), 8, 120, 20, "##E5E5E5", "#D0D0D0", "#1ABC9C", "#E74C3C"); + FlatUI::setScrollBarQss(ui->ram_scrollArea->horizontalScrollBar(), 8, 120, 20, "#E5E5E5", "#D0D0D0", "#1ABC9C", "#E74C3C"); + FlatUI::setScrollBarQss(ui->flash_scrollArea->verticalScrollBar(), 8, 120, 20, "#E5E5E5", "#D0D0D0", "#1ABC9C", "#E74C3C"); + FlatUI::setScrollBarQss(ui->flash_scrollArea->horizontalScrollBar(), 8, 120, 20, "#E5E5E5","#D0D0D0", "#1ABC9C", "#E74C3C"); + + FlatUI::setScrollBarQss(ui->ram_table->horizontalScrollBar(), 8, 120, 20, "#E5E5E5", "#D0D0D0", "#1ABC9C", "#E74C3C"); + FlatUI::setScrollBarQss(ui->ram_table->verticalScrollBar(), 8, 120, 20, "#E5E5E5", "#D0D0D0", "#1ABC9C", "#E74C3C"); + FlatUI::setScrollBarQss(ui->flash_table->horizontalScrollBar(), 8, 120, 20, "#E5E5E5","#D0D0D0", "#1ABC9C", "#E74C3C"); + FlatUI::setScrollBarQss(ui->flash_table->verticalScrollBar(), 8, 120, 20, "#E5E5E5", "#D0D0D0", "#1ABC9C", "#E74C3C"); + + FlatUI::setProgressQss(ui->ram_used_bar, 20,12,16, "#747976", "#1ABC9C");//#FAEC9C",#FFF5E7 + FlatUI::setProgressQss(ui->flash_used_bar, 20,12,16, "#747976", "#1ABC9C"); + + main_window=this; + + +map_path="P:/AT32_F403A_FreeRTOS/MDK_Project"; +project_path="P:/AT32_F403A_FreeRTOS/MDK_Project"; + ui->map_path->setText(map_path); + ui->project_path->setText(project_path); + + ram_pieseries=new QPieSeries(); + flash_pieseries=new QPieSeries(); + + cpu= new parse_keil_project(ui->project_path->text()); + cpu->to_parse_keil_project(ui->project_path->text()); + if(cpu->getCpu_core_name()!="8051") + { + map= new parse_map_from_keil( ui->map_path->text(),cpu->IRAM.getBase_addr(),cpu->IRAM.getMax_size(),cpu->IROM.getBase_addr(),cpu->IROM.getMax_size()); + if(map->to_parse_map_from_keil(ui->map_path->text())) + map_calculate_size_by_address(map); + + }else { + + m51 =new parse_m51_from_keil(ui->map_path->text(),cpu->IRAM.getMax_size(),cpu->XRAM.getMax_size(),cpu->IROM.getMax_size()); + + + } + + ram_chart=new QChart(); + flash_chart=new QChart(); + + + + + +//QChartView + + +ram_chart->addSeries(ram_pieseries); +ram_chart->setTitle("文件内存分布饼图"); +ram_chart->legend()->hide(); +// Set the theme to one of the predefined themes +ram_chart->setTheme(QChart::ChartThemeQt); +ram_chart->setBackgroundBrush(QBrush(Qt::gray)); + +flash_chart->addSeries(flash_pieseries); +flash_chart->setTitle("文件flash分布饼图"); +flash_chart->legend()->hide(); +// Set the theme to one of the predefined themes +flash_chart->setTheme(QChart::ChartThemeQt); +flash_chart->setBackgroundBrush(QBrush(Qt::gray)); + +ui->ram_chart_view->setChart(ram_chart); +ui->ram_chart_view->setRubberBand(QChartView::RectangleRubberBand); + +ui->flash_chart_view->setChart(flash_chart); +ui->flash_chart_view->setRubberBand(QChartView::RectangleRubberBand); + + update_cpu_info(); + + + if(cpu->getCpu_core_name()!="8051") + { + update_map_info(); + }else { + update_m51_info(); + } + + + +} + + + +void MainWindow::map_calculate_size_by_address(parse_map_from_keil* map) +{ + + + for(auto ram:map->ram_list) + { + if(ram->getMax_size()>100*1024*1024) + { + + uint64_t recent_base=cpu->IRAM.getBase_addr()+cpu->IRAM.getMax_size(); + + for(auto recent_ram :map->ram_list) + { + if(recent_ram->getBase_addr()>ram->getBase_addr()) + { + if(recent_ram->getBase_addr()-ram->getBase_addr()getBase_addr()) + recent_base=recent_ram->getBase_addr(); + } + + } + + ram->setMax_size(recent_base-ram->getBase_addr()); + } + } + for(auto flash:map->flash_list) + { + if(flash->getMax_size()>100*1024*1024) + { + + uint64_t recent_base=cpu->IROM.getBase_addr()+cpu->IROM.getMax_size(); + for(auto recent_flash :map->flash_list) + { + + if(recent_flash->getBase_addr()>flash->getBase_addr()) + { + + if(recent_flash->getBase_addr()-flash->getBase_addr()getBase_addr()) + recent_base=recent_flash->getBase_addr(); + + } + } + flash->setMax_size(recent_base-flash->getBase_addr()); + } + } + +} + +void MainWindow::on_btn_set_project_path_clicked() +{ + //获取选择的目录路径 + QString selectedDir=QFileDialog::getExistingDirectory(this,"选择一个目录","./",QFileDialog::ShowDirsOnly); + //若目录路径不为空 + if (!selectedDir.isEmpty()) + { + //将路径中的斜杠替换为反斜杠 + selectedDir = selectedDir.replace(QRegExp("\\"), "/"); + //显示选择的目录路径 + ui->project_path->setText(selectedDir); + ui->map_path->setText(selectedDir); + } + +} + + +void MainWindow::set_bar_style(QProgressBar *bar,float per) +{ + if( per/1.0>0.85) + { + FlatUI::setProgressQss(bar, 20,12,16, "#747976", "#E74C3C"); + + }else if( per>0.75) + { + FlatUI::setProgressQss(bar, 20,12,16, "#747976", "#F9D927"); + + } + else + { + FlatUI::setProgressQss(bar, 20,12,16, "#747976", "#1ABC9C"); + } + +} + +void MainWindow::on_btn_set_map_path_clicked() +{ + //获取选择的目录路径 + QString selectedDir=QFileDialog::getExistingDirectory(this,"选择一个目录","./",QFileDialog::ShowDirsOnly); + //若目录路径不为空 + if (!selectedDir.isEmpty()) + { + //将路径中的斜杠替换为反斜杠 + selectedDir = selectedDir.replace(QRegExp("\\"), "/"); + //显示选择的目录路径 + ui->map_path->setText(selectedDir); + } +} + +void MainWindow::on_update_info_clicked() +{ + + + if(cpu!=nullptr) + { + delete cpu; + cpu=nullptr; + } + cpu= new parse_keil_project(ui->project_path->text()); + + if(cpu->to_parse_keil_project(ui->project_path->text())) + update_cpu_info(); + + if(cpu->getCpu_core_name()!="8051") + { + + if(map!=nullptr) + { + delete map; + map=nullptr; + } + map= new parse_map_from_keil(ui->map_path->text(),cpu->IRAM.getBase_addr(),cpu->IRAM.getMax_size(),cpu->IROM.getBase_addr(),cpu->IROM.getMax_size()); + if(map->to_parse_map_from_keil(ui->map_path->text())) + map_calculate_size_by_address(map); + + update_map_info(); + + }else { + + + + if(m51!=nullptr) + { + delete m51; + m51=nullptr; + } + m51 =new parse_m51_from_keil(ui->map_path->text(),cpu->IRAM.getMax_size(),cpu->XRAM.getMax_size(),cpu->IROM.getMax_size()); + + if(m51->to_parse_m51_from_keil(ui->map_path->text())) + update_m51_info(); + + } + + + + +} + +void MainWindow::on_ram_table_itemSelectionChanged() +{ + QList selectedItems = ui->ram_table->selectedItems(); + + + // Reset all pie slices to not exploded (not highlighted) + foreach (QPieSlice* slice, ram_pieseries->slices()) { + slice->setExploded(false); + slice->setLabelVisible(false); + + } + foreach (QTableWidgetItem* item, selectedItems) { + int row = item->row(); +// qDebug() << row; + + QPieSlice *slice = ram_pieseries->slices().at(row); + slice->setExploded();//突出这一块 + slice->setLabelVisible();//设置这一块可见数据 + + + } + +} + +void MainWindow::on_flash_table_itemSelectionChanged() +{ + QList selectedItems = ui->flash_table->selectedItems(); + + + // Reset all pie slices to not exploded (not highlighted) + foreach (QPieSlice* slice, flash_pieseries->slices()) { + slice->setExploded(false); + slice->setLabelVisible(false); + + } + foreach (QTableWidgetItem* item, selectedItems) { + int row = item->row(); +// qDebug() << row; + + QPieSlice *slice = flash_pieseries->slices().at(row); + slice->setExploded();//突出这一块 + slice->setLabelVisible();//设置这一块可见数据 + + + } +} + + + +void MainWindow::update_cpu_info(void) +{ + ui->cpu_name->setTitle(cpu->getCpu_name()); + ui->cpu_core->setText("单片机核心:"+cpu->getCpu_core_name()); + ui->cpu_colck->setText(QString().sprintf("最高主频:%.2f MHz",cpu->getCpu_max_clock()/1000000.0)); + ui->iram->setText(QString().sprintf("内部ram 地址:%#x 容量:%.2f KB",cpu->IRAM.getBase_addr(),cpu->IRAM.getMax_size()/1024.0)); + ui->flash->setText(QString().sprintf("内部flash 地址:%#x 容量:%.2f KB",cpu->IROM.getBase_addr(),cpu->IROM.getMax_size()/1024.0)); + +} + + + +void MainWindow::clearLayout(QLayout* layout) { + QLayoutItem* item; + while ((item = layout->takeAt(0))) { + QWidget* widget = item->widget(); + if (widget) { + layout->removeWidget(widget); // 将小部件从布局中移除 + widget->setParent(nullptr); // 设置父对象为nullptr,避免悬挂指针问题 + delete widget; // 删除小部件并释放内存 + } + delete item; // 删除布局项 + } +} + + +void MainWindow::update_m51_info(void) +{ + uint64_t ram_all_max_size=0; + uint64_t ram_all_used_size=0; + uint64_t ram_min_base_addr=m51->ram_list.at(0)->getBase_addr(); + + uint64_t flash_all_max_size=0; + uint64_t flash_all_used_size=0; + uint64_t flash_min_base_addr=m51->flash_list.at(0)->getBase_addr(); + uint16_t i; + + + clearLayout(ui->ram_scrollAreaWidgetContents->layout()); + + // 移除并释放布局中的所有小部件 + + clearLayout(ui->flash_scrollAreaWidgetContents->layout()); + + // 移除并释放布局中的所有小部件 + + + for(i=0;iram_list.size();i++) + { + + ram_all_used_size+=m51->ram_list.at(i)->getUsed_size(); + ram_all_max_size+=m51->ram_list.at(i)->getMax_size(); + if(ram_min_base_addr>m51->ram_list.at(0)->getBase_addr()) + ram_min_base_addr=m51->ram_list.at(i)->getBase_addr(); + ui->ram_scrollAreaWidgetContents->layout()->addWidget(m51->ram_list.at(i)); + } + + + + ui->ram_addr->setText(QString().sprintf("地址:%#x",ram_min_base_addr)); + ui->ram_used_bar->setRange(0,ram_all_max_size); + ui->ram_used_bar->setValue(ram_all_used_size); + ui->ram_remain->setText(QString().sprintf("剩余:%.2f B",ram_all_max_size/10.0-ram_all_used_size/10.0)); + if(ram_all_max_size/10.0<=1024) + { + ui->ram_used->setText(QString().sprintf("占用:%.2f B / (%.2f B)",ram_all_used_size/10.0,ram_all_max_size/10.0)); + }else + { + ui->ram_used->setText(QString().sprintf("占用:%.2f B / (%.2f KB)",ram_all_used_size/1024.0,ram_all_max_size/10.0/1024.0)); + } + +set_bar_style(ui->ram_used_bar,ram_all_used_size/1.0/ram_all_max_size/1.0); + + for(i=0;iflash_list.size();i++) + { + flash_all_used_size+=m51->flash_list.at(i)->getUsed_size(); + flash_all_max_size+=m51->flash_list.at(i)->getMax_size(); + if(flash_min_base_addr>m51->flash_list.at(0)->getBase_addr()) + flash_min_base_addr=m51->flash_list.at(i)->getBase_addr(); + ui->flash_scrollAreaWidgetContents->layout()->addWidget(m51->flash_list.at(i)); + } + + ui->flash_addr->setText(QString().sprintf("地址:%#x",flash_min_base_addr)); + ui->flash_used_bar->setRange(0,flash_all_max_size); + ui->flash_used_bar->setValue(flash_all_used_size); + ui->flash_remain->setText(QString().sprintf("剩余:%.2f B",flash_all_max_size/10.0-flash_all_used_size/10.0)); + if(flash_all_max_size/10.0<=1024) + { + ui->flash_used->setText(QString().sprintf("占用:%.2f B / (%.2f B)",flash_all_used_size/10.0,flash_all_max_size/10.0)); + }else + { + ui->flash_used->setText(QString().sprintf("占用:%.2f B / (%.2f KB)",flash_all_used_size/1024.0,flash_all_max_size/10.0/1024.0)); + } +set_bar_style(ui->flash_used_bar,ram_all_used_size/1.0/ram_all_max_size/1.0); + +} + +void MainWindow::setPieSliceStyle(QPieSlice* slice, qreal percentage, qreal maxPercentage) +{ + + // Define an array of custom green colors to represent different percentage ranges + QColor colors[] = { + QColor("#D1FF4D"), // Light Green Yellow + QColor("#C0FF3E"), // Greenish Yellow + QColor("#ADFF2F"), // Green Yellow + QColor("#7CFC00"), // Lawn Green + QColor("#00FF00"), // Lime Green + QColor("#008000"), // Green + QColor("#006400"), // Dark Green + }; + + // Calculate the relative percentage compared to the maxPercentage + qreal relativePercentage = (percentage / maxPercentage) * 100.0; + + // Determine the index of the color based on relative percentage + int colorIndex = qMin(int(relativePercentage) / (100 / (sizeof(colors) / sizeof(colors[0]))), sizeof(colors) / sizeof(colors[0]) - 1); + + // Set the color of the slice based on the color index + slice->setColor(colors[colorIndex]); + + +} + +void MainWindow::update_map_info(void) +{ + + uint64_t ram_all_max_size=0; + uint64_t ram_all_used_size=0; + uint64_t ram_min_base_addr=map->ram_list.at(0)->getBase_addr(); + + uint64_t flash_all_max_size=0; + uint64_t flash_all_used_size=0; + uint64_t flash_min_base_addr=map->flash_list.at(0)->getBase_addr(); + uint16_t i; + + + clearLayout(ui->ram_scrollAreaWidgetContents->layout()); +// // 移除并释放布局中的所有小部件 + clearLayout(ui->flash_scrollAreaWidgetContents->layout()); +// // 移除并释放布局中的所有小部件 +for(uint64_t row_cnt=0;row_cntram_table->rowCount();row_cnt++) +{ + + ui->ram_table->removeRow(row_cnt); +} + +ram_pieseries->clear(); + +for(uint64_t row_cnt=0;row_cntflash_table->rowCount();row_cnt++) +{ + ui->flash_table->removeRow(row_cnt); +} + +flash_pieseries->clear(); + + + + for(i=0;iram_list.size();i++) + { + + ram_all_used_size+=map->ram_list.at(i)->getUsed_size(); + ram_all_max_size+=map->ram_list.at(i)->getMax_size(); + if(ram_min_base_addr>map->ram_list.at(0)->getBase_addr()) + ram_min_base_addr=map->ram_list.at(i)->getBase_addr(); + ui->ram_scrollAreaWidgetContents->layout()->addWidget(map->ram_list.at(i)); + } + + + + ui->ram_addr->setText(QString().sprintf("地址:%#x",ram_min_base_addr)); + ui->ram_used_bar->setRange(0,ram_all_max_size); + ui->ram_used_bar->setValue(ram_all_used_size); + ui->ram_remain->setText(QString().sprintf("剩余:%llu B",ram_all_max_size-ram_all_used_size)); + if(ram_all_max_size<=1024*1024) + { + ui->ram_used->setText(QString().sprintf("占用:%.2f KB / (%.2f KB)",ram_all_used_size/1024.0,ram_all_max_size/1024.0)); + }else + { + ui->ram_used->setText(QString().sprintf("占用:%.4f MB / (%.4f MB)",ram_all_used_size/1024.0/1024.0,ram_all_max_size/1024.0/1024.0)); + } + +set_bar_style(ui->ram_used_bar,ram_all_used_size/1.0/ram_all_max_size/1.0); + + + for(i=0;iflash_list.size();i++) + { + flash_all_used_size+=map->flash_list.at(i)->getUsed_size(); + flash_all_max_size+=map->flash_list.at(i)->getMax_size(); + if(flash_min_base_addr>map->flash_list.at(0)->getBase_addr()) + flash_min_base_addr=map->flash_list.at(i)->getBase_addr(); + ui->flash_scrollAreaWidgetContents->layout()->addWidget(map->flash_list.at(i)); + } + + ui->flash_addr->setText(QString().sprintf("地址:%#x",flash_min_base_addr)); + ui->flash_used_bar->setRange(0,flash_all_max_size); + ui->flash_used_bar->setValue(flash_all_used_size); + ui->flash_remain->setText(QString().sprintf("剩余:%llu B",flash_all_max_size-flash_all_used_size)); + if(flash_all_max_size<=1024*1024) + { + ui->flash_used->setText(QString().sprintf("占用:%.2f KB / (%.2f KB)",flash_all_used_size/1024.0,flash_all_max_size/1024.0)); + }else + { + ui->flash_used->setText(QString().sprintf("占用:%.4f MB / (%.4f MB)",flash_all_used_size/1024.0/1024.0,flash_all_max_size/1024.0/1024.0)); + } + + set_bar_style(ui->flash_used_bar,ram_all_used_size/1.0/ram_all_max_size/1.0); + + + + + QList info_lsit= map->getInfo_list(); + uint64_t all_ram_size = map->getAll_ram_size(); + uint64_t all_flash_size =map->getAll_flash_size(); + uint64_t ram_row=0; + uint64_t flash_row=0; + for(auto item:info_lsit) + { + if(item->RW_Data.toUInt()+item->ZI_Data.toUInt()!=0) + { + writeTableData(ram_table,ram_row,0,item->Object_Name); + writeTableData(ram_table,ram_row,1,QString::number(item->RW_Data.toUInt()+item->ZI_Data.toUInt())); + writeTableData(ram_table,ram_row,3,item->RW_Data); + writeTableData(ram_table,ram_row,4,item->ZI_Data); + all_ram_size+=item->RW_Data.toUInt()+item->ZI_Data.toUInt(); + ram_row++; + } + + if(item->Code.toUInt()+item->RO_Data.toUInt()+item->RW_Data.toUInt()!=0) + { + + + writeTableData(flash_table,flash_row,0,item->Object_Name); + writeTableData(flash_table,flash_row,1,QString::number(item->Code.toUInt()+item->RO_Data.toUInt()+item->RW_Data.toUInt())); + writeTableData(flash_table,flash_row,3,item->Code); + writeTableData(flash_table,flash_row,4,item->RO_Data); + writeTableData(flash_table,flash_row,5,item->RW_Data); + all_flash_size+=item->Code.toUInt()+item->RO_Data.toUInt()+item->RW_Data.toUInt(); + flash_row++; + } + } + + + + + + + + ui->ram_per->setTitle(QString().sprintf("used_ram=RW+ZI=%llu",all_ram_size)); + ui->flash_per->setTitle(QString().sprintf("used_flash=RW+Code+RO=%llu",all_flash_size)); + + + + + + for(uint64_t row_cnt=0;row_cntram_table->rowCount();row_cnt++) + { + writeTableData(ram_table,row_cnt,2,QString().sprintf("%05.2f%%",ui->ram_table->item(row_cnt,1)->text().toUInt()*100.0/all_ram_size/1.0)); + } + + for(uint64_t row_cnt=0;row_cntflash_table->rowCount();row_cnt++) + { + writeTableData(flash_table,row_cnt,2,QString().sprintf("%05.2f%%",ui->flash_table->item(row_cnt,1)->text().toUInt()*100.0/all_flash_size/1.0)); + } + + ui->ram_table->sortByColumn(2,Qt::SortOrder::DescendingOrder); + ui->flash_table->sortByColumn(2,Qt::SortOrder::DescendingOrder); + + + + for(uint64_t row_cnt=0;row_cntram_table->rowCount();row_cnt++) + { + + + + + QPieSlice *slice =ram_pieseries->append(ui->ram_table->item(row_cnt,0)->text()+":"+ui->ram_table->item(row_cnt,2)->text(),ui->ram_table->item(row_cnt,1)->text().toUInt()); + + setPieSliceStyle(slice,ui->ram_table->item(row_cnt,2)->text().split("%")[0].toFloat(),ui->ram_table->item(0,2)->text().split("%")[0].toFloat()); + + + + } + + for(uint64_t row_cnt=0;row_cntflash_table->rowCount();row_cnt++) + { + QPieSlice *slice =flash_pieseries->append(ui->flash_table->item(row_cnt,0)->text()+":"+ui->flash_table->item(row_cnt,2)->text(),ui->flash_table->item(row_cnt,1)->text().toUInt()); + setPieSliceStyle(slice,ui->flash_table->item(row_cnt,2)->text().split("%")[0].toFloat(),ui->flash_table->item(0,2)->text().split("%")[0].toFloat()); + + } + + + + + +} + + + + + + + + + + +QString MainWindow::readTableData(ui_table_t table,int row, int column) + { + QString data; + QTableWidget* tableWidget ; + if( table==ram_table)tableWidget=ui->ram_table; + else tableWidget=ui->flash_table; + + if (row < tableWidget->rowCount() && column columnCount()) { + QTableWidgetItem *item =tableWidget->item(row, column); + if (item) { + data = item->text(); +// qDebug() << "Data at (" << row << ", " << column << "): " << data; + } + } + return data; + } + + + void MainWindow::writeTableData(ui_table_t table,int row, int column, const QString &data) + { + + + QTableWidget* tableWidget=nullptr; + if (table == ram_table) + { + + tableWidget=ui->ram_table; + + } + else if (table == flash_table) + { + tableWidget = ui->flash_table; + + } + else + { + qDebug() << "Invalid table specified."; + return; + } + + + if (row >= tableWidget->rowCount()) + { + tableWidget->setRowCount(row + 1); + } + if (column >= tableWidget->columnCount()) + { + tableWidget->setColumnCount(column + 1); + } + + if (!tableWidget->item(row, column)) + { + QTableWidgetItem *newItem = new QTableWidgetItem(data); + tableWidget->setItem(row, column, newItem); + } + else + { + tableWidget->item(row, column)->setText(data); + } + + + + + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + +void MainWindow::titleDblClick() +{ + on_btnMenu_Max_clicked(); +} + +void MainWindow::windowStateChange(bool max) +{ + ui->btnMenu_Max->setText(max ? "还原" : "最大"); +} + +void MainWindow::on_btnMenu_Min_clicked() +{ +#ifdef Q_OS_MACOS + this->setWindowFlags(this->windowFlags() & ~Qt::FramelessWindowHint); +#endif + this->showMinimized(); +} + +void MainWindow::on_btnMenu_Max_clicked() +{ + if (this->isMaximized()) { + this->showNormal(); + ui->btnMenu_Max->setText("最大"); + } else { + this->showMaximized(); + ui->btnMenu_Max->setText("还原"); + } +} + +void MainWindow::on_btnMenu_Close_clicked() +{ + this->close(); +} + +void MainWindow::on_gitee_index_clicked() +{ + QDesktopServices::openUrl(QUrl("https://gitee.com/nikolan")); // Change the URL to the desired webpage + +} diff --git a/mainwindow.h b/mainwindow.h new file mode 100644 index 0000000..c9aca34 --- /dev/null +++ b/mainwindow.h @@ -0,0 +1,68 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include "framelessmainwindow.h" + +#include "parse_keil_project.h" +#include "parse_map_from_keil.h" +#include "parse_m51_from_keil.h" + +#include +extern QString project_path; +extern QString map_path; +extern bool only_printf; + +QT_CHARTS_USE_NAMESPACE +namespace Ui { +class MainWindow; +} +typedef enum{ram_table,flash_table}ui_table_t; +class MainWindow : public FramelessMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + void setPieSliceStyle(QPieSlice* slice, qreal percentage, qreal maxPercentage); +void set_bar_style(QProgressBar *bar,float per); +void update_cpu_info(void); +void update_map_info(void); +void update_m51_info(void); +QString readTableData(ui_table_t table,int row, int column); +void writeTableData(ui_table_t table,int row, int column, const QString &data); +void map_calculate_size_by_address(parse_map_from_keil* map); +Ui::MainWindow *ui; + +QPieSeries *ram_pieseries=nullptr; +QPieSeries *flash_pieseries=nullptr; +QChart* ram_chart=nullptr; +QChart* flash_chart=nullptr; + + +private: + + +void clearLayout(QLayout* layout); + parse_keil_project* cpu=nullptr; + parse_map_from_keil* map=nullptr; + parse_m51_from_keil* m51=nullptr; + +private slots: + void initForm(); + void titleDblClick(); + void windowStateChange(bool max); + +private slots: + void on_btnMenu_Min_clicked(); + void on_btnMenu_Max_clicked(); + void on_btnMenu_Close_clicked(); + void on_btn_set_project_path_clicked(); + void on_btn_set_map_path_clicked(); + void on_update_info_clicked(); + void on_ram_table_itemSelectionChanged(); + void on_flash_table_itemSelectionChanged(); + void on_gitee_index_clicked(); +}; + +#endif // MAINWINDOW_H diff --git a/mainwindow.ui b/mainwindow.ui new file mode 100644 index 0000000..87dc562 --- /dev/null +++ b/mainwindow.ui @@ -0,0 +1,965 @@ + + + MainWindow + + + + 0 + 0 + 800 + 600 + + + + MainWindow + + + + color:#3f3f3f; +background: #ECF0F1; + + + + 10 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 0 + 40 + + + + color:#ffffff; +background:#34495E; +border-top-left-radius:8px; +border-top-right-radius:8px; + + + + 0 + + + 0 + + + 6 + + + 0 + + + + + + + + + :/KDA_Logo.ico:/KDA_Logo.ico + + + + 40 + 40 + + + + + + + + + 0 + 0 + + + + 一个极客开源::keil开发助手 + + + + + + + + 0 + 0 + + + + + 16777215 + 28 + + + + + 10 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 60 + 30 + + + + + 60 + 16777215 + + + + ArrowCursor + + + Qt::NoFocus + + + 最小化 + + + QPushButton { +border-style: none; +padding: 8px; +border-radius: 5px; +color: #FFFFFF; +background: #3498DB; +} + +QPushButton:hover { +color: #FFF5E7; +background: #2E86C1; +} + +QPushButton:pressed { +color: #F5A996; +background: #1B4F72; +} + + + + +QPushButton:disabled{ + background-color: #34495E; + border-color: #D6D6D6; +} + + + + 最小 + + + + + + + + 0 + 0 + + + + + 60 + 30 + + + + + 60 + 16777215 + + + + Qt::NoFocus + + + QPushButton{border-style:none;padding:8px;border-radius:5px;color:#E6F8F5;background:#1ABC9C;} +QPushButton:hover{color:#FFFFFF;background:#2EE1C1;} +QPushButton:pressed{color:#A7EEE6;background:#16A086;} + +QPushButton:disabled{ + background-color: #34495E; + border-color: #D6D6D6; +} + + + + 最大 + + + + + + + + 0 + 0 + + + + + 60 + 30 + + + + + 60 + 16777215 + + + + ArrowCursor + + + Qt::NoFocus + + + 关闭 + + + QPushButton{border-style:none;padding:8px;border-radius:5px;color:#FFFFFF;background:#E74C3C;} +QPushButton:hover{color:#FFF5E7;background:#EC7064;} +QPushButton:pressed{color:#F5A996;background:#DC2D1A;} + + +QPushButton:disabled{ + background-color: #34495E; + border-color: #D6D6D6; +} + + + + 关闭 + + + + + + + + + + + + + Qt::Vertical + + + + + 0 + 1 + + + + 手动操作 + + + + + + QPushButton { +border-style: none; +padding: 8px; +border-radius: 5px; +color: #FFFFFF; +background: #3498DB; +} + +QPushButton:hover { +color: #FFF5E7; +background: #2E86C1; +} + +QPushButton:pressed { +color: #F5A996; +background: #1B4F72; +} + + + + +QPushButton:disabled{ + background-color: #34495E; + border-color: #D6D6D6; +} + + + + 选择目录 + + + + + + + 工程路径: + + + + + + + + + + QPushButton { +border-style: none; +padding: 8px; +border-radius: 5px; +color: #FFFFFF; +background: #3498DB; +} + +QPushButton:hover { +color: #FFF5E7; +background: #2E86C1; +} + +QPushButton:pressed { +color: #F5A996; +background: #1B4F72; +} + + + + +QPushButton:disabled{ + background-color: #34495E; + border-color: #D6D6D6; +} + + + + 选择目录 + + + + + + + map文件路径: + + + + + + + + + + QPushButton{border-style:none;padding:8px;border-radius:5px;color:#E6F8F5;background:#1ABC9C;} +QPushButton:hover{color:#FFFFFF;background:#2EE1C1;} +QPushButton:pressed{color:#A7EEE6;background:#16A086;} + +QPushButton:disabled{ + background-color: #34495E; + border-color: #D6D6D6; +} + + + + 手动更新数据 + + + + + + + + + 0 + 6 + + + + +QTabWidget::pane { + + background-color:#34495E; + border-top: 2px solid #C2C7CB; + /* position: absolute; + top: -0.5em; */ + border-color: #9B9B9B; + color: rgb(255, 255, 255); + +} + + +QTabWidget::tab-bar { + + background-color: #34495E; + color: rgb(255, 255, 255); + /* alignment: center; */ + +} + + + +QTabBar { + background-color: #34495E; + color: rgb(255, 255, 255); +} + +QTabBar::tab:selected { + + + background-color:#2EE1C1; +color: rgb(255, 255, 255); + + +} + +QTabBar::tab:!selected{ + +background-color:#34495E; +color: rgb(255, 255, 255); + +} + + + + 3 + + + + 构建后信息 + + + + + + Qt::Vertical + + + + + 0 + 1 + + + + mcu_name + + + + + + 最高主频: + + + + + + + 内部flash 大小: + + + + + + + 内部ram 大小: + + + + + + + 核心: + + + + + + + + + 0 + 3 + + + + Qt::Horizontal + + + + 按map文件识别的ram + + + + + + true + + + + + 0 + 0 + 360 + 131 + + + + + + + + + + all_ram + + + + + + 地址:0xxxxxx + + + Qt::AlignCenter + + + + + + + 24 + + + + + + + 占用: + + + + + + + 还剩: + + + + + + + + + + + 按map文件识别的flash + + + + + + true + + + + + 0 + 0 + 360 + 131 + + + + + + + + + + all_flash + + + + + + 地址:0xxxxxx + + + Qt::AlignCenter + + + + + + + 24 + + + + + + + 占用: + + + + + + + 还剩: + + + + + + + + + + + + + + + + ram占比 + + + + + + + 0 + 1 + + + + project::xxx cup:xxxx + + + + + + Qt::Horizontal + + + + + 1 + 0 + + + + + 文件名 + + + + + 占用ram大小B + + + + + 占用ram比例% + + + + + RW + + + + + ZI + + + + + + + 2 + 0 + + + + 占用饼图 + + + Qt::AlignCenter + + + + + + + + + + + + + + + + + flash占比 + + + + + + + 0 + 1 + + + + project::xxx cup:xxxx + + + + + + Qt::Horizontal + + + + + 1 + 0 + + + + + 文件名 + + + + + 占用flash大小B + + + + + 占用flash比例% + + + + + Code + + + + + RO + + + + + RW + + + + + + + 2 + 0 + + + + 占用饼图 + + + Qt::AlignCenter + + + + + + + + + + + + + + + + + 更多 + + + + + + + 4 + 0 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'SimSun'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">这是一个开源项目,基于GPLv2开源协议。</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">你可以通过来gitee开源仓库地址,</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">来反馈BUG或者提供优化代码来帮助维护这个项目,</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">或者给予建议或者告诉作者你想要的功能。</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">参与了代码的奉献,实现某些功能或优化了某些代码,</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">会更新到readme的奉献者名单。</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">或者能力赞助该项目开发的,</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">会更新到readme赞助者名单。</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">该软件将永久免费,开源不易,谢谢大家的支持,</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">你的支持是我更新维护项目的动力。</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">留言:ageek_nikola </p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">邮箱:2503865771@qq.com</p></body></html> + + + + + + + 一个极客ageek开源 + + + + + + + 0 + 0 + + + + + + + + :/KDA_Logo.ico:/KDA_Logo.ico + + + + 60 + 60 + + + + + + + + + + + + :/gitee.png:/gitee.png + + + + 200 + 60 + + + + + + + + 点击以上图标跳转到gitee开源地址 + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'SimSun'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">KDA</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">keil_development_assistant</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">keil开发助手</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#0055ff;">主要解决的问题:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#0055ff;">无需反复翻查map文件,</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#0055ff;">让你的嵌入式软件能更好的进行优化</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#00aa00;">主要实现的功能:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#00aa00;">- 分析ram和flash占用百分比</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#00aa00;">- 分析已使用的ram和flash的各文件占比</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + + + + + + + + + + + + + + + + + QChartView + QGraphicsView +
qchartview.h
+
+
+ + + + +
diff --git a/only_run_by_file.cpp b/only_run_by_file.cpp new file mode 100644 index 0000000..6f0a790 --- /dev/null +++ b/only_run_by_file.cpp @@ -0,0 +1,110 @@ +#include "only_run_by_file.h" + +only_run_by_file::only_run_by_file(QObject *parent) : QObject(parent), + runFileName("run"), + closeFileName("close") +{ + + + + // 如果 run 文件已经存在,则删除 + if (QFile::exists(runFileName)) { + QFile::remove(runFileName); + + // 检测 close 文件是否存在的定时器 + closeTimer = new QTimer(this); + connect(closeTimer, &QTimer::timeout, this, &only_run_by_file::checkCloseFile); + closeTimer->start(300); // 每 300 毫秒执行一次检测 + }else + createRunFile(); + + + + + // 检测 run 文件是否存在的定时器 + timer = new QTimer(this); + connect(timer, &QTimer::timeout, this, &only_run_by_file::checkRunFile); + timer->start(800); // 每 800 毫秒执行一次检测 +} + +void only_run_by_file::createCloseFile() +{ + // 创建 close 文件 + QFile file(closeFileName); + file.open(QIODevice::WriteOnly); + file.close(); +} + +void only_run_by_file::createRunFile() +{ + // 创建 run 文件 + QFile file(runFileName); + file.open(QIODevice::WriteOnly); + file.close(); +} + +void only_run_by_file::deleteCloseFile() +{ + // 如果 close 文件已经存在,则删除 + if (QFile::exists(closeFileName)) { + QFile::remove(closeFileName); + } + +} +void only_run_by_file::deleteRunFile() +{ + // 如果 run 文件已经存在,则删除 + if (QFile::exists(runFileName)) { + QFile::remove(runFileName); + } +} + + + +void only_run_by_file::checkRunFile() +{ + // 检测 run 文件是否存在 + if (!QFile::exists(runFileName)) { + // 文件不存在,采集关闭操作并创建 close 文件 + deleteCloseFile(); + // 创建 close 文件 + createCloseFile(); + emit runFileDeleted(); + } +} + +void only_run_by_file::checkCloseFile() +{ + static uint8_t cnt=0; + + if(cnt<3) + { + + cnt++; + // 检测 close 文件是否存在 + if (QFile::exists(closeFileName)) { + // 发出信号,通知检测到 close 文件 + closeTimer->stop(); + // 如果 close 文件已经存在,则删除 + deleteCloseFile(); + // 创建 run 文件 + createRunFile(); + + + + emit closeFileDetected(); + + + } + + }else + { + cnt=0; + // 如果 close 文件已经存在,则删除 + deleteCloseFile(); + // 创建 run 文件 + createRunFile(); + emit closeFileDetected(); + } + +} diff --git a/only_run_by_file.h b/only_run_by_file.h new file mode 100644 index 0000000..47989cc --- /dev/null +++ b/only_run_by_file.h @@ -0,0 +1,32 @@ +#ifndef ONLY_RUN_BY_FILE_H +#define ONLY_RUN_BY_FILE_H + +#include +#include +#include + +class only_run_by_file : public QObject +{ + Q_OBJECT +public: + explicit only_run_by_file(QObject *parent = nullptr); + +private: + const QString runFileName; + const QString closeFileName; + + void createCloseFile(); + void createRunFile(); + void deleteCloseFile(); + void deleteRunFile(); + QTimer* closeTimer; + QTimer* timer ; +signals: + void runFileDeleted(); + void closeFileDetected(); + +public slots: + void checkRunFile(); + void checkCloseFile(); +}; +#endif // ONLY_RUN_BY_FILE_H diff --git a/parse_keil_project.cpp b/parse_keil_project.cpp new file mode 100644 index 0000000..702e38e --- /dev/null +++ b/parse_keil_project.cpp @@ -0,0 +1,260 @@ +#include "parse_keil_project.h" + + +#include +#include +#include +#include +#include + + +#include "find_path.h" + + +QString parse_keil_project::find_project_path(const QString& dir_path) +{ + +return find_path::find_file_path(dir_path,".uvproj"); + +} + +parse_keil_project::parse_keil_project(QString path) +{ + + + + IRAM.setName("IRAM"); + XRAM.setName("XRAM"); + IROM.setName("IROM"); + +// to_parse_keil_project(path); + + + +} + + +bool parse_keil_project::to_parse_keil_project(QString path) +{ + project_path=path; + QString file_path; + + if(path.contains(".uvproj")) + { + parse_project_file(path); + return true; + } + + file_path=find_project_path(project_path); + qDebug()<"< +#include + + +class parse_keil_project +{ + +public: + + parse_keil_project(QString path); + bool to_parse_keil_project(QString path); + QString find_project_path(const QString& dir_path); + bool parse_project_file(QString path); + bool parse_cpu_info(const QString& cpu_info); + + bool parse_info_item_storage(const QString& info_item,use_percentage_bar& storage ); + bool parse_info_item_core_name(const QString& info_item); + bool parse_info_item_max_clock(const QString& info_item); + + QString getCpu_core_name() const; + + uint64_t getCpu_max_clock() const; + + QString getProject_path() const; + void setProject_path(const QString &value); + + use_percentage_bar IRAM; + use_percentage_bar IROM; + use_percentage_bar XRAM; + + + QString getCpu_name() const; + +private: + QString project_path; + // uint64_t iram_base; +// uint64_t xram_base; +// uint64_t irom_base; +// uint64_t iram_size; +// uint64_t xram_size; +// uint64_t irom_size; +QString cpu_name; + QString cpu_core_name; + uint64_t cpu_max_clock; + +}; + +#endif // PARSE_KEIL_PROJECT_H diff --git a/parse_m51_from_keil.cpp b/parse_m51_from_keil.cpp new file mode 100644 index 0000000..4cbda55 --- /dev/null +++ b/parse_m51_from_keil.cpp @@ -0,0 +1,180 @@ +#include "parse_m51_from_keil.h" + +#include +#include +#include "find_path.h" + +#include + +parse_m51_from_keil::parse_m51_from_keil(QString path,uint64_t iram_max_size,uint64_t xram_max_size, + uint64_t irom_max_size) +{ + +iram_max=iram_max_size; +xram_max=xram_max_size; +irom_max=irom_max_size; + +//to_parse_m51_from_keil(path); +} + +bool parse_m51_from_keil::to_parse_m51_from_keil(QString path) +{ + + + QString file_path=find_m51_path(path); +qDebug()<3){ + + parse_m51_file(file_path); + return true; + } + else{ + qDebug()<<"路径错误"; + return false; + } +} + +QString parse_m51_from_keil::find_m51_path(const QString &dir_path) +{ + + + QString m51_file_path; + m51_file_path=find_path::find_file_path(dir_path,".m51"); + if(m51_file_path.length()<3) + m51_file_path=find_path::find_file_path(dir_path,".M51"); + + return m51_file_path; +} + +bool parse_m51_from_keil::parse_m51_file(QString path) +{ + QFile file(path); + + iram=new use_percentage_bar(nullptr); + xram=new use_percentage_bar(nullptr); + irom=new use_percentage_bar(nullptr); + + + iram->setName("iram"); + iram->setStorage(mc8051); + iram->setBase_addr(0); + xram->setName("xram"); + xram->setStorage(mc8051); + xram->setBase_addr(0); + xram->setMax_size(0); + + irom->setName("irom"); + irom->setStorage(mc8051); + irom->setBase_addr(0); + + iram->setMax_size(iram_max*10.0); + + xram->setMax_size(xram_max*10.0); + + irom->setMax_size(irom_max*10.0); + + + bool is_Image_component_sizes=false; + bool is_Totals=false; + +// info_list.clear(); + + for(auto ram:ram_list) + { + delete ram; + } + ram_list.clear(); + + for(auto flash:flash_list) + { + delete flash; + } + + flash_list.clear(); + + + if (!file.open(QIODevice::ReadOnly)) + { + qDebug()<<"open fail"<setUsed_size((str_list[i].split("=")[1].toFloat())*10.0); + xram->setRemain_size(xram->getMax_size()-xram->getUsed_size()); + }else if(str_list[i].contains("XDATA")) + { + xram->setUsed_size((str_list[i].split("=")[1].toFloat())*10.0); + xram->setRemain_size(xram->getMax_size()-xram->getUsed_size()); + }else if(str_list[i].contains("data")) + { + + + iram->setUsed_size((str_list[i].split("=")[1].toFloat())*10.0); + iram->setRemain_size(iram->getMax_size()-iram->getUsed_size()); + }else if(str_list[i].contains("DATA")) + { + iram->setUsed_size((str_list[i].split("=")[1].toFloat())*10.0); + iram->setRemain_size(iram->getMax_size()-iram->getUsed_size()); + }else if(str_list[i].contains("code")) + { + irom->setUsed_size((str_list[i].split("=")[1].toFloat())*10.0); + irom->setRemain_size(irom->getMax_size()-irom->getUsed_size()); + }else if(str_list[i].contains("code")) + { + irom->setUsed_size((str_list[i].split("=")[1].toFloat())*10.0); + irom->setRemain_size(irom->getMax_size()-irom->getUsed_size()); + } + + } + + + } +// else if(str.contains("Image component sizes")) +// { +// is_Image_component_sizes=true; +//// qDebug()<getMax_size()>0) + ram_list.append(xram); + flash_list.append(irom); + + qDebug()<<"ram:"; + for(auto ram:ram_list) + { + ram->print_bar_8051(); + } + qDebug()<<"flash:"; + for(auto flash:flash_list) + { + flash->print_bar_8051(); + } + + +} diff --git a/parse_m51_from_keil.h b/parse_m51_from_keil.h new file mode 100644 index 0000000..040ca56 --- /dev/null +++ b/parse_m51_from_keil.h @@ -0,0 +1,32 @@ +#ifndef PARSE_M51_FROM_KEIL_H +#define PARSE_M51_FR0M_KEIL_H + +#include +#include "use_percentage_bar.h" +#include + +class parse_m51_from_keil +{ +public: + parse_m51_from_keil(QString path,uint64_t iram_max_size,uint64_t xram_max_size, + uint64_t irom_max_size); + + uint64_t all_ram_size=0; + uint64_t all_flash_size=0; + + uint64_t iram_max; + uint64_t xram_max; + uint64_t irom_max; + use_percentage_bar* iram; + use_percentage_bar* xram; + use_percentage_bar* irom; + QListram_list; + QListflash_list; + + + bool to_parse_m51_from_keil(QString path); + QString find_m51_path(const QString& dir_path); + bool parse_m51_file(QString path); +}; + +#endif // PARSE_M51_FROM_KEIL_H diff --git a/parse_map_from_keil.cpp b/parse_map_from_keil.cpp new file mode 100644 index 0000000..d0ca8f5 --- /dev/null +++ b/parse_map_from_keil.cpp @@ -0,0 +1,330 @@ +#include "parse_map_from_keil.h" +#include +#include +#include +#include +#include +#include "find_path.h" +#include + + +#include "mainwindow.h" +#include "ui_mainwindow.h" +extern MainWindow* main_window; + +QString parse_map_from_keil::find_map_path(const QString& dir_path) +{ + + + QString map_file_path; + map_file_path=find_path::find_file_path(dir_path,".map"); + if(map_file_path.length()<3) + map_file_path=find_path::find_file_path(dir_path,".MAP"); + + return map_file_path; + + + +} + +bool parse_map_from_keil::parse_excution_region_info(QString info_string) +{ + +// storage_type_t storage=ram; + use_percentage_bar* storage=new use_percentage_bar(nullptr); + storage->setStorage(flash); + for(auto keyword:ram_keyword) + { + if(info_string.contains(keyword)) + { +// qDebug()<setStorage(ram); + } + } + + + + + info_string.remove("Execution Region", Qt::CaseInsensitive);//去除"Execution Region" + info_string.remove(QChar(' '), Qt::CaseInsensitive);//去除" " + + storage->setName(info_string.split("(")[0]); + QStringList info_list =info_string.split("(")[1].split(","); + + + + for(auto info :info_list) + { + QStringList info_value; + info.remove(QChar(','), Qt::CaseInsensitive);//去除"," + info.remove(QChar(' '), Qt::CaseInsensitive);//去除")" + + + if(info.contains("Exec")||info.contains("Base")) + { + info_value =info.split(":"); + info_value[1].remove(QChar('x'), Qt::CaseInsensitive);//去除"x" + storage->setBase_addr(info_value[1].toUInt(nullptr,16)); +// qDebug()<getBase_addr()>iram_base&&storage->getBase_addr()setStorage(ram); + else if(storage->getBase_addr()>irom_base&&storage->getBase_addr()setStorage(flash); + + }else if(info.contains("Size")) + { + + info_value =info.split(":"); + info_value[1].remove(QChar('x'), Qt::CaseInsensitive);//去除"x" + + storage->setUsed_size(info_value[1].toUInt(nullptr,16)); +// qDebug()<setMax_size(info_value[1].toUInt(nullptr,16)); +// qDebug()<getStorage()==ram) + ram_list.append(storage); + else + flash_list.append(storage); + + +} + +bool parse_map_from_keil::parse_map_file(QString path){ + + QFile file(path); + + bool is_Image_component_sizes=false; + bool is_Totals=false; + + + for(auto info:info_list) + { + delete info; + } + info_list.clear(); + + for(auto ram:ram_list) + { + delete ram; + } + ram_list.clear(); + + + for(auto flash:flash_list) + { + delete flash; + } + flash_list.clear(); + + + + if (!file.open(QIODevice::ReadOnly)) + { + qDebug()<<"open fail"<7&&item_data[7].contains("Totals")) + { + + continue; + + } + } + + item_data[1].toUInt(&is_number); + if(is_number) + { + + image_item_t* item=new image_item_t(); + item->Code=QString::number(item_data[0].toInt());//item_data[1].toUInt()(inc.data是包含在code内的) + item->RO_Data=item_data[2]; + item->RW_Data=item_data[3]; + item->ZI_Data=item_data[4]; + item->Debug=item_data[5]; + item->Object_Name=item_data[6]; + + if(item->Object_Name.contains(".l")) + continue; + else if (item->Object_Name.contains("(")) { + item->Object_Name=item->Object_Name=item_data[6]+item_data[7]; + + } + + info_list.append(item); + + } + + } + + + + } + } + } + + + qDebug()<<"ram:"; + for(auto ram:ram_list) + { + ram->print_bar(); + } + qDebug()<<"flash:"; + for(auto flash:flash_list) + { + flash->print_bar(); + } + + file.close(); + + +} + +QString parse_map_from_keil::getMap_path() const +{ + return map_path; +} + +void parse_map_from_keil::setMap_path(const QString &value) +{ + map_path = value; +} + +QList parse_map_from_keil::getInfo_list() const +{ + return info_list; +} + +void parse_map_from_keil::setInfo_list(const QList &value) +{ + info_list = value; +} + +uint64_t parse_map_from_keil::getAll_ram_size() const +{ + return all_ram_size; +} + +uint64_t parse_map_from_keil::getAll_flash_size() const +{ + return all_flash_size; +} + + + +bool parse_map_from_keil::to_parse_map_from_keil(QString path) +{ + + map_path=path; + QString file_path; + + + if(path.contains(".map")||path.contains(".MAP")) + { + parse_map_file(path); + return true; + } + + + + file_path=find_map_path(path); + qDebug()<3) + { + parse_map_file(file_path); + return true; + }else + { + qDebug()<<"路径错误"; + return false; + } +} + +parse_map_from_keil::parse_map_from_keil(QString path, uint64_t to_iram_base, + uint64_t to_iram_max_size, + uint64_t to_irom_base, + uint64_t to_irom_max_size) +{ + + + iram_base=to_iram_base; + iram_max_size=to_iram_base; + irom_base=to_irom_base; + irom_max_size= to_irom_max_size; + +//to_parse_map_from_keil(path); + +} diff --git a/parse_map_from_keil.h b/parse_map_from_keil.h new file mode 100644 index 0000000..41da210 --- /dev/null +++ b/parse_map_from_keil.h @@ -0,0 +1,74 @@ +#ifndef PARSE_MAP_FROM_KEIL_H +#define PARSE_MAP_FROM_KEIL_H + +#include +#include "use_percentage_bar.h" +#include + + +typedef struct {QString fn_name;QString file_name; uint64_t size;}map_item; + + +typedef struct image_item { + + QString Code; + QString RO_Data; + QString RW_Data; + QString ZI_Data; + QString Debug; + QString Object_Name; + +}image_item_t; + +class parse_map_from_keil +{ + +public: + bool to_parse_map_from_keil(QString path); + parse_map_from_keil(QString path, + uint64_t to_iram_base, + uint64_t to_iram_max_size, + uint64_t to_irom_base, + uint64_t to_irom_max_size +); + QString find_map_path(const QString& dir_path); + bool parse_excution_region_info(QString info_string); + bool parse_map_file(QString path); + + + QListram_list; + QListflash_list; + + + QString getMap_path() const; + void setMap_path(const QString &value); + + QList getInfo_list() const; + void setInfo_list(const QList &value); + + uint64_t getAll_ram_size() const; + + uint64_t getAll_flash_size() const; + +private: + + + uint64_t iram_base; + uint64_t iram_max_size; + + uint64_t irom_base; + uint64_t irom_max_size; + + + + uint64_t all_ram_size=0; + uint64_t all_flash_size=0; +//,"HEAP","STACK","heap","stack" + QList ram_keyword={"ER$$","RW_","ER_RW","ER_ZI"}; + QList flash_keyword={"RO","FLASH","flash","ro","text","TEXT"}; + + QString map_path; + QList info_list; +}; + +#endif // PARSE_MAP_FROM_KEIL_H diff --git a/use_percentage_bar.cpp b/use_percentage_bar.cpp new file mode 100644 index 0000000..3b2643b --- /dev/null +++ b/use_percentage_bar.cpp @@ -0,0 +1,301 @@ +#include "use_percentage_bar.h" +#include "ui_use_percentage_bar.h" +#include +#include +#include + +use_percentage_bar::use_percentage_bar(QWidget *parent) : + QWidget(parent), + ui(new Ui::use_percentage_bar) +{ + ui->setupUi(this); + + FlatUI::setProgressQss(ui->used_bar, 20,12,16, "#747976", "#1ABC9C"); + +} +void use_percentage_bar::set_bar_style(QProgressBar *bar,float per) +{ + if( per/1.0>0.85) + { + FlatUI::setProgressQss(bar, 20,12,16, "#747976", "#E74C3C"); + + }else if( per>0.75) + { + FlatUI::setProgressQss(bar, 20,12,16, "#747976", "#F9D927"); + + } + else + { + FlatUI::setProgressQss(bar, 20,12,16, "#747976", "#1ABC9C"); + } + +} +use_percentage_bar::~use_percentage_bar() +{ + delete ui; +} +void use_percentage_bar::print_bar_8051(void) +{ + +if(max_size==0) +{ + qDebug()<<"erro:max=0"; + return; +} + uint8_t i; + QString bar_str; + qDebug()<name->setTitle(name); +} + +storage_type_t use_percentage_bar::getStorage() const +{ + return storage; +} + +void use_percentage_bar::setStorage(const storage_type_t &value) +{ + storage = value; +} + +uint64_t use_percentage_bar::getBase_addr() const +{ + return base_addr; +} + +void use_percentage_bar::setBase_addr(const uint64_t &value) +{ + base_addr = value; + ui->addr->setText(QString().sprintf("地址:%#x", base_addr)); +} + +uint64_t use_percentage_bar::getLoad_addr() const +{ + return load_addr; +} + +void use_percentage_bar::setLoad_addr(const uint64_t &value) +{ + load_addr = value; +} + +uint64_t use_percentage_bar::getLoad_max_size() const +{ + return load_max_size; +} + +void use_percentage_bar::setLoad_max_size(const uint64_t &value) +{ + load_max_size = value; + +} + +uint64_t use_percentage_bar::getUsed_size() const +{ + return used_size; +} + +void use_percentage_bar::setUsed_size(const uint64_t &value) +{ + used_size = value; + if(max_size!=0) + { + ui->used_bar->setRange(0,max_size); + ui->used_bar->setValue(used_size); + + if(storage==mc8051) + { + if(max_size/10.0<=1024) + { + ui->used->setText(QString().sprintf("占用:%.2f B / (%.2f B)",used_size/10.0,max_size/10.0)); + + } + else + { + ui->used->setText(QString().sprintf("占用:%.2f B / (%.2f KB)",used_size/10.0,max_size/10.0/1024.0)); + + } + setRemain_size(max_size-used_size); + }else + { + if(max_size<=1024*1024) + { + ui->used->setText(QString().sprintf("占用:%.2f KB / (%.2f KB)",used_size/1024.0,max_size/1024.0)); + + } + else + { + ui->used->setText(QString().sprintf("占用:%.4f MB / (%.4f MB)",used_size/1024.0/1024.0,max_size/1024.0/1024.0)); + + } + setRemain_size(max_size-used_size); + } +set_bar_style(ui->used_bar,used_size/1.0/max_size/1.0); + + + } +} + +uint64_t use_percentage_bar::getMax_size() const +{ + return max_size; +} + +void use_percentage_bar::setMax_size(const uint64_t &value) +{ + max_size = value; + + if(max_size!=0) + { + + ui->used_bar->setRange(0,max_size); + ui->used_bar->setValue(used_size); + + + if(storage==mc8051) + { + + + if(max_size/10.0<=1024) + { + ui->used->setText(QString().sprintf("占用:%.2f B / (%.2f B)",used_size/10.0,max_size/10.0)); + + }else + { + ui->used->setText(QString().sprintf("占用:%.2f B / (%.2f KB)",used_size/10.0,max_size/10.0/1024.0)); + + } + setRemain_size(max_size-used_size); + }else + { + if(max_size<=1024*1024) + { + ui->used->setText(QString().sprintf("占用:%.2f KB / (%.2f KB)",used_size/1024.0,max_size/1024.0)); + + }else + { + ui->used->setText(QString().sprintf("占用:%.4f MB / (%.4f MB)",used_size/1024.0/1024.0,max_size/1024.0/1024.0)); + + } + setRemain_size(max_size-used_size); + } +set_bar_style(ui->used_bar,used_size/1.0/max_size/1.0); + + + } + +} + +uint64_t use_percentage_bar::getRemain_size() const +{ + return remain_size; +} + +void use_percentage_bar::setRemain_size(const uint64_t &value) +{ + remain_size = value; + if(storage==mc8051) + { + ui->remain->setText(QString().sprintf("剩余:%.2f B",remain_size/10.0)); + }else + { + ui->remain->setText(QString().sprintf("剩余:%llu B",remain_size)); + } +} + diff --git a/use_percentage_bar.h b/use_percentage_bar.h new file mode 100644 index 0000000..5c0241d --- /dev/null +++ b/use_percentage_bar.h @@ -0,0 +1,61 @@ +#ifndef USE_PERCENTAGE_BAR_H +#define USE_PERCENTAGE_BAR_H + +#include +#include +namespace Ui { +class use_percentage_bar; +} +typedef enum storage_type {ram,flash,mc8051 }storage_type_t; + +class use_percentage_bar : public QWidget +{ + Q_OBJECT + +public: + explicit use_percentage_bar(QWidget *parent = nullptr); + ~use_percentage_bar(); + + + void print_bar(void); +void print_bar_8051(void); + + QString getName() const; + void setName(const QString &value); + + storage_type_t getStorage() const; + void setStorage(const storage_type_t &value); + + uint64_t getBase_addr() const; + void setBase_addr(const uint64_t &value); + + uint64_t getLoad_addr() const; + void setLoad_addr(const uint64_t &value); + + uint64_t getLoad_max_size() const; + void setLoad_max_size(const uint64_t &value); + + uint64_t getUsed_size() const; + void setUsed_size(const uint64_t &value); + + uint64_t getMax_size() const; + void setMax_size(const uint64_t &value); + + uint64_t getRemain_size() const; + void setRemain_size(const uint64_t &value); + +private: + Ui::use_percentage_bar *ui; + + QString name; + storage_type_t storage; + uint64_t base_addr; + uint64_t load_addr; + uint64_t load_max_size; + uint64_t used_size; + uint64_t max_size; + uint64_t remain_size; +void set_bar_style(QProgressBar *bar,float per); +}; + +#endif // USE_PERCENTAGE_BAR_H diff --git a/use_percentage_bar.ui b/use_percentage_bar.ui new file mode 100644 index 0000000..9696235 --- /dev/null +++ b/use_percentage_bar.ui @@ -0,0 +1,61 @@ + + + use_percentage_bar + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + + RAM/Flash + + + + + + 地址:0x0000000 + + + Qt::AlignCenter + + + + + + + 24 + + + + + + + 占用: + + + + + + + 还剩: + + + + + + + + + + +