Qt5.14封装 QTextEdit可现实行号和列号

概述

  • 开发操作系统: win11
  • Qt版本: 5.14
  • 封装之初心, 用于显示网络和串口收到的源码数据, 十六进制显示,每一帧显示一行

功能

  • 可显示行号和列号
  • 可指定列数与行数
  • 显示滚动条

界面组成

  • 全部由QTextEdit组成, 共四个。 其中,左上角的 没有用到。 仅仅起到了占位的作用。 见下图

显示范例

  • 下面用于显示源码范例

用法

  • 直接调用append 函数即可

控件组成

  • 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 &quot;Consolas&quot;;</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>

头文件

  • 头文件名: ListCtrlEx.h
  • 源码
#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

源文件

  • 源文件名: ListCtrlEx.cpp
  • 源码:
#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);
		});
}

posted @ 2023-03-16 17:46  mohist  阅读(1056)  评论(0编辑  收藏  举报