概述
- 开发操作系统: win11
- Qt版本: 5.14
- 封装之初心, 用于显示网络和串口收到的源码数据, 十六进制显示,每一帧显示一行
功能
界面组成
- 全部由QTextEdit组成, 共四个。 其中,左上角的 没有用到。 仅仅起到了占位的作用。 见下图
显示范例
- 下面用于显示源码范例
用法
控件组成
- UI文件,数量:1个
- 头文件, 数量: 1个
- 源文件, 数量: 1个
UI文件源码
- ui文件名: ListCtrlEx.ui
- 文件源码:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ListCtrlExClass</class>
<widget class="QWidget" name="ListCtrlExClass">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>410</width>
<height>197</height>
</rect>
</property>
<property name="windowTitle">
<string>ListCtrlEx</string>
</property>
<property name="styleSheet">
<string notr="true">font: 10pt "Consolas";</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,20">
<property name="spacing">
<number>0</number>
</property>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="QTextEdit" name="te_header_2">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>20</height>
</size>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QTextEdit" name="te_line_id">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAsNeeded</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="QTextEdit" name="te_header">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>20</height>
</size>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
</widget>
</item>
<item>
<widget class="QTextEdit" name="te_input">
<property name="enabled">
<bool>true</bool>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAsNeeded</enum>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>
头文件
#ifndef list_ctrl_ex_h
#define list_ctrl_ex_h
#include <QWidget>
namespace Ui { class ListCtrlExClass; };
/// ----------------------------------------------------------------------------
/// @brief: 自封控件,用于显示源码
/// ----------------------------------------------------------------------------
class ListCtrlEx : public QWidget
{
enum
{
/// 默认最大行数
MAX_ROW_COUNT = 20,
};
Q_OBJECT
public:
explicit ListCtrlEx(QWidget *parent = Q_NULLPTR);
~ListCtrlEx();
/// ----------------------------------------------------------------------------
/// @brief: 初始化
/// @param: const int max_row_count - 最大行数
/// @return: void - 无
///
/// ----------------------------------------------------------------------------
void init(const uint max_row_count);
/// ----------------------------------------------------------------------------
/// @brief: 追加显示数据, 但是不显示行ID
/// @param: const QString & str - str
/// @return: void - 无
///
/// ----------------------------------------------------------------------------
void append(const QString& str);
/// ----------------------------------------------------------------------------
/// @brief: 追加显示
/// @param: const unsigned char * pbuf - pbuf
/// @param: const unsigned int pbuf_len - pbuf_len
/// @return: void - 无
///
/// ----------------------------------------------------------------------------
void append(const uchar* pbuf, const uint pbuf_len);
/// ----------------------------------------------------------------------------
/// @brief: 清空显示的数据
/// @return: void - 无
///
/// ----------------------------------------------------------------------------
void clear();
/// ----------------------------------------------------------------------------
/// @brief: 显示单行
/// @param: const QString & str_show - str_show
/// @return: void - 无
///
/// ----------------------------------------------------------------------------
void setDisplaySingleRow(const QString& str_show );
/// ----------------------------------------------------------------------------
/// @brief: 获取第一行字符串
/// @return: QT_NAMESPACE::QString - 无
///
/// ----------------------------------------------------------------------------
QString firstLineString();
/// ----------------------------------------------------------------------------
/// @brief: 设置垂直滚动条是否可用
/// @param: bool is_enabled - is_enabled
/// @return: void - 无
///
/// ----------------------------------------------------------------------------
void setHeaderScrollBarVisible(bool is_enabled);
/// ----------------------------------------------------------------------------
/// @brief: 设置垂直滚动条是否可用
/// @param: bool is_enabled - is_enabled
/// @return: void - 无
///
/// ----------------------------------------------------------------------------
void setInputScrollBarVisible(bool is_enabled);
private slots:
/// ----------------------------------------------------------------------------
/// @brief: 输入的水平滚动条变化了
/// @param: int cur_value - cur_value
/// @return: void - 无
///
/// ----------------------------------------------------------------------------
void slotTextInputhorizontalScroolbarValueChanged(int cur_value);
/// 输入框的文本变化了
void slotTextInputTextChanged();
void slotCursorPositionChanged();
private:
/// ----------------------------------------------------------------------------
/// @brief: 初始化UI
/// @return: void - 无
///
/// ----------------------------------------------------------------------------
void initUI();
private:
/// UI
Ui::ListCtrlExClass*ui = nullptr;
/// id列是否显示
bool m_idColumnVisible = true;
/// 最大行数
int m_maxRowCount = MAX_ROW_COUNT;
/// 最大列数
int m_maxColumnCount = 1024 * 3;
/// 上一行
int m_lastLineID = 1;
};
#endif /// list_ctrl_ex_h
源文件
#include <QTextBlock>
#include <QDebug>
#include <QScrollBar>
#include "ListCtrlEx.h"
#include "ui_ListCtrlEx.h"
ListCtrlEx::ListCtrlEx(QWidget* parent)
: QWidget(parent)
{
ui = new(std::nothrow) Ui::ListCtrlExClass();
ui->setupUi(this);
initUI();
init(m_maxRowCount);
}
ListCtrlEx::~ListCtrlEx()
{
if (ui)
delete ui;
ui = nullptr;
}
/// ----------------------------------------------------------------
/// @brief: 初始化
/// ----------------------------------------------------------------
void ListCtrlEx::init(const uint max_row_count)
{
if (0 == max_row_count )
return;
m_maxRowCount = max_row_count;
ui->te_input->document()->setMaximumBlockCount(m_maxRowCount);
}
/// ----------------------------------------------------------------
/// @brief: 追加显示数据
/// ----------------------------------------------------------------
void ListCtrlEx::append(const QString& str)
{
ui->te_input->append(str.toUpper());
}
/// ----------------------------------------------------------------
/// @brief: 追加显示
/// ----------------------------------------------------------------
void ListCtrlEx::append(const uchar* pbuf , const uint pbuf_len)
{
/// 超过最大行数, 则清空
{
int cur_row_count = ui->te_input->document()->lineCount();
if (m_maxRowCount < cur_row_count)
{
ui->te_input->clear();
m_lastLineID = 0;
}
}
///// 不能超过显示的最长长度
int column_count = pbuf_len;
if (pbuf_len > m_maxColumnCount)
{
column_count = m_maxColumnCount;
}
QString str_value;
for (int index = 0; index < column_count; ++index)
{
int width = 2;
if (255 < index)
{
width = 3;
}
str_value += QString("%1 ").arg(pbuf[index] , width , 16 , QLatin1Char('0'));
}
/// 显示数据
ui->te_input->append(str_value.toUpper());
QScrollBar* pscrollbar = ui->te_input->verticalScrollBar();
pscrollbar->setValue(pscrollbar->maximum());
}
/// ----------------------------------------------------------------
/// @brief: 清空显示的数据
/// ----------------------------------------------------------------
void ListCtrlEx::clear()
{
ui->te_input->clear();
m_lastLineID = 0;
}
/// ----------------------------------------------------------------
/// @brief: 显示单行
/// ----------------------------------------------------------------
void ListCtrlEx::setDisplaySingleRow(const QString& str_show)
{
ui->te_input->clear();
m_lastLineID = 0;
ui->te_input->append(str_show);
}
/// ----------------------------------------------------------------
/// @brief: 获取第一行字符串
/// ----------------------------------------------------------------
QString ListCtrlEx::firstLineString()
{
if (ui)
{
if (ui->te_input)
{
QString str_ret = ui->te_input->document()->findBlockByLineNumber(0).text();
return str_ret;
}
}
return QString("");
}
/// ----------------------------------------------------------------
/// @brief: 设置垂直滚动条是否可用
/// ----------------------------------------------------------------
void ListCtrlEx::setHeaderScrollBarVisible(bool is_enabled)
{
if (true == is_enabled)
ui->te_header->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
}
/// ----------------------------------------------------------------
/// @brief: 设置垂直滚动条是否可用
/// ----------------------------------------------------------------
void ListCtrlEx::setInputScrollBarVisible(bool is_enabled)
{
if (true == is_enabled)
ui->te_input->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
}
/// ----------------------------------------------------------------
/// @brief: 输入的水平滚动条变化了
/// ----------------------------------------------------------------
void ListCtrlEx::slotTextInputhorizontalScroolbarValueChanged(int cur_value)
{
ui->te_header->horizontalScrollBar()->setValue(cur_value);
}
/// --------------------------------------------------------------------------------
/// @brief: 输入框的文本变化了
/// --------------------------------------------------------------------------------
void ListCtrlEx::slotTextInputTextChanged()
{
int input_row = ui->te_input->document()->lineCount();
if (input_row == m_lastLineID)
{
return;
}
ui->te_line_id->blockSignals(true);
ui->te_input->blockSignals(true);
//方法1
int countOfRow = 0;
int temp = input_row;
while (temp != 0)
{
temp = temp / 10;
++countOfRow;
}
//ui->te_line_id->setFixedWidth(ui->te_line_id->font().pixelSize() * countOfRow + 10);
//方法2
ui->te_line_id->clear();
QString str;
++input_row;
for (int i = 1; i < input_row; ++i)
{
str.append(QString("%1\n").arg(i));/// , 4, 10, QLatin1Char(' ')));
}
ui->te_line_id->setPlainText(str);
//
QScrollBar* pscrollbar = ui->te_line_id->verticalScrollBar();
pscrollbar->setValue(pscrollbar->maximum());
//qDebug() << "\n\nstr=" << str;
m_lastLineID = ui->te_input->document()->lineCount();
ui->te_line_id->verticalScrollBar()->setValue(ui->te_input->verticalScrollBar()->value());
ui->te_line_id->blockSignals(false);
ui->te_input->blockSignals(false);
}
/// --------------------------------------------------------------------------------
/// @brief: ListCtrlEx::slotCursorPositionChanged
/// --------------------------------------------------------------------------------
void ListCtrlEx::slotCursorPositionChanged()
{
ui->te_line_id->blockSignals(true);
ui->te_input->blockSignals(true);
ui->te_line_id->verticalScrollBar()->setValue(ui->te_input->verticalScrollBar()->value());
ui->te_line_id->blockSignals(false);
ui->te_input->blockSignals(false);
}
/// ----------------------------------------------------------------
/// @brief: 初始化UI
/// ----------------------------------------------------------------
void ListCtrlEx::initUI()
{
/// ----------------------------------------------------------------------------
/// 绑定信号槽, 当输入区域的滚动条动了,通知header跟着变化
connect(ui->te_input->horizontalScrollBar(), &QScrollBar::valueChanged, this, &ListCtrlEx::slotTextInputhorizontalScroolbarValueChanged);
/// 设置进制换行
ui->te_header->setWordWrapMode(QTextOption::NoWrap);
/// 设置进制换行
ui->te_input->setWordWrapMode(QTextOption::NoWrap);
ui->te_input->setReadOnly(true);
/// 设置最大行数是1000
ui->te_input->document()->setMaximumBlockCount(m_maxRowCount);
/// 设置表头
{
/// 显示表头
QString str_header;
for (int index = 1; index <= m_maxColumnCount; ++index)
{
int width = 2;
if (255 < index)
{
width = 3;
}
str_header += QString("%1 ").arg(index, width, 16, QLatin1Char('0'));
}
str_header += " ";
str_header = str_header.toUpper();
ui->te_header->setText(str_header);
}
connect(ui->te_input, &QTextEdit::textChanged, this, &ListCtrlEx::slotTextInputTextChanged);
connect(ui->te_line_id, &QTextEdit::cursorPositionChanged, this, &ListCtrlEx::slotCursorPositionChanged);
ui->te_line_id->verticalScrollBar()->hide();
ui->te_line_id->horizontalScrollBar()->hide();
//QString str_tmp = QString("%1\n").arg(1, 4, 10, QLatin1Char(' '));
//ui->te_line_id->insertPlainText(str_tmp);
ui->te_line_id->setFocusPolicy(Qt::NoFocus);
ui->te_line_id->setContextMenuPolicy(Qt::NoContextMenu);
connect(ui->te_input->verticalScrollBar(), &QScrollBar::valueChanged, [&](int value)
{
ui->te_line_id->verticalScrollBar()->setValue(value);
});
}