代码拉取完成,页面将自动刷新
#include <QPainter>
#include <QScrollBar>
#include <QPaintEvent>
#include <QDebug>
#include "hexwidget.h"
HexWidget::HexWidget(QWidget *parent)
: QAbstractScrollArea(parent),
m_size(0),
m_selectPosition(0),
m_selectSize(0),
m_bytesPerLine(16)
{
#ifdef Q_OS_WIN32
setFont(QFont("Courier", 10));
#else
setFont(QFont("Monospace", 10));
#endif
init();
}
HexWidget::~HexWidget()
{
m_data.clear();
}
void HexWidget::setData(const QByteArray &data)
{
m_data.clear();
m_data = data;
m_size = data.length();
m_selectPosition = 0;
m_selectSize = 0;
init();
viewport()->update();
}
void HexWidget::setSelect(qint64 pos, int len)
{
m_selectPosition = pos;
m_selectSize = len;
ensureSelectVisible();
viewport()->update();
}
QByteArray HexWidget::getSelectData()
{
return m_data.mid(m_selectPosition, m_selectSize);
}
qint64 HexWidget::findBytes(const QByteArray &data, bool next)
{
if (data.isEmpty() || m_data.isEmpty()) return -1;
if (next) {
int index = m_data.indexOf(data, m_selectPosition);
if (index < 0 || index >= m_selectPosition + m_selectSize) {
return index;
}
return m_data.indexOf(data, m_selectPosition + m_selectSize);
} else {
int index = m_selectPosition;
if (m_data.mid(index, data.length()) == data) {
index--;
}
return m_data.lastIndexOf(data, index);
}
}
// Handle events
QSize HexWidget::sizeHint() const
{
int w = m_margin + m_labelWidth + m_HexWidth + m_textWidth;
return QSize(w + 23, m_lineHeight * 16);
}
void HexWidget::mousePressEvent(QMouseEvent * event)
{
// 判断是否左键
if (event->button() != Qt::LeftButton) {
QAbstractScrollArea::mousePressEvent(event);
return;
}
const int xOffset = horizontalScrollBar()->value();
int x = event->pos().x() + xOffset;
x -= m_margin + m_labelWidth + m_margin / 2;
x /= m_columnWidth;
if (x < 0) {
return;
} else if (x >= m_bytesPerLine) {
x = event->pos().x() + xOffset;
x -= m_margin + m_labelWidth + m_HexWidth;
x /= m_charWidth;
if (x < 0) x = 0; // 不太可能再小于0了
else if (x >= m_bytesPerLine) return;
}
const int topLine = verticalScrollBar()->value();
int y = event->pos().y();
y = y / m_lineHeight + topLine;
qint64 pos = y * m_bytesPerLine + x;
emit onSelect(pos);
}
void HexWidget::paintEvent(QPaintEvent *event)
{
// qDebug() << "HexWidget::" << __func__ << "() in";
QPainter painter(viewport());
painter.setBackgroundMode(Qt::TransparentMode);
const int topLine = verticalScrollBar()->value();
const int xOffset = horizontalScrollBar()->value();
// 地址与数据之间的竖线
const int x1 = -xOffset + m_margin + m_labelWidth - m_margin / 2 - 1;
const int x2 = x1 + m_HexWidth;
painter.setPen(palette().color(QPalette::WindowText));
painter.drawLine(x1, 0, x1, viewport()->height());
painter.drawLine(x2, 0, x2, viewport()->height());
// 列条纹
for (int i = 0; i < m_bytesPerLine; i += 2) {
int bg_x = -xOffset + m_margin + m_labelWidth + m_columnWidth * i + m_margin / 2;
QRect r(bg_x, 0, m_columnWidth, viewport()->height());
painter.fillRect(event->rect() & r, palette().alternateBase());
}
// 地址
painter.setPen(palette().color(QPalette::WindowText));
for (int i = 0; i < m_numVisibleLines; i++) {
qint64 pos = m_bytesPerLine * (i + topLine);
QString address = QString("%1").arg(pos, m_addressBytes, 16, QChar('0')).toUpper();
if (pos + m_bytesPerLine > m_selectPosition && pos < m_selectPosition + m_selectSize) {
QRect r(-xOffset + m_margin, m_lineHeight * i, m_labelWidth - m_margin, m_lineHeight);
painter.save();
painter.setPen(palette().highlightedText().color());
painter.fillRect(r, palette().highlight());
painter.drawText(-xOffset + m_margin, m_lineHeight * i + m_ascent, address);
painter.restore();
continue;
}
painter.drawText(-xOffset + m_margin, m_lineHeight * i + m_ascent, address);
}
// 数据
painter.setPen(palette().color(QPalette::Text));
QByteArray data = m_data.mid(topLine * m_bytesPerLine, m_numVisibleLines * m_bytesPerLine);
int textStart = -xOffset + m_margin + m_labelWidth;
for (int i = 0; i < m_numVisibleLines; i++) {
if (m_bytesPerLine * i >= data.length()) break;
QString hex, text;
for (int j = 0; j < m_bytesPerLine; j++) {
if (m_bytesPerLine * i + j >= data.length()) break;
char c = data[m_bytesPerLine * i + j];
hex.append(QString(" %1").arg((unsigned char) c, 2, 16, QChar('0')));
if (c < ' ' || c > '~') c = '.';
text.append(c);
}
hex = hex.toUpper();
int y = m_lineHeight * i + m_ascent;
qint64 pos = m_bytesPerLine * (i + topLine);
if (pos + m_bytesPerLine > m_selectPosition && pos < m_selectPosition + m_selectSize) {
int start = 0, end = m_bytesPerLine;
if (pos < m_selectPosition) {
start = m_selectPosition - pos;
}
if (pos + m_bytesPerLine > m_selectPosition + m_selectSize) {
end = m_selectPosition + m_selectSize - pos;
}
int x1 = textStart + m_columnWidth * start;
int x2 = textStart + m_HexWidth + m_charWidth * start;
QRect r1(x1 + m_margin / 2, m_lineHeight * i, (end - start) * m_columnWidth, m_lineHeight);
QRect r2(x2, m_lineHeight * i, (end - start) * m_charWidth, m_lineHeight);
if (start > 0) {
painter.drawText(textStart, y, hex.mid(0, start * 3));
painter.drawText(textStart + m_HexWidth, y, text.mid(0, start));
}
painter.save();
painter.setPen(QPen(Qt::white));
painter.fillRect(r1, QColor(0x0078D7));
painter.fillRect(r2, QColor(0x0078D7));
painter.drawText(x1, y, hex.mid(start * 3, (end - start) * 3));
painter.drawText(x2, y, text.mid(start, end - start));
painter.restore();
if (end < m_bytesPerLine && end < hex.length() / 3) {
painter.drawText(textStart + m_columnWidth * end, y, hex.mid(end * 3));
painter.drawText(textStart + m_HexWidth + m_charWidth * end, y, text.mid(end));
}
} else {
painter.drawText(textStart, y, hex);
painter.drawText(textStart + m_HexWidth, y, text);
}
}
// qDebug() << "HexWidget::" << __func__ << "() out";
}
void HexWidget::resizeEvent(QResizeEvent *)
{
init();
}
void HexWidget::changeEvent(QEvent *)
{
init();
viewport()->update();
}
// Private utility functions
void HexWidget::init()
{
// qDebug() << "HexWidget::" << __func__ << "() in";
QFontMetrics fm(fontMetrics());
m_descent = fm.descent();
m_ascent = fm.ascent();
m_lineHeight = fm.lineSpacing();
m_charWidth = fm.horizontalAdvance(QChar('M'));
m_margin = fm.horizontalAdvance(QChar(' '));
m_columnWidth = 2 * m_charWidth + m_margin;
m_numLines = (m_size - 1) / m_bytesPerLine + 1;
m_numVisibleLines = (viewport()->height() - 1) / m_lineHeight + 1;
m_addressBytes = QString("%1").arg(m_size, 0, 16).length();
if (m_addressBytes < 4) m_addressBytes = 4;
m_labelWidth = m_addressBytes * m_charWidth + m_margin;
m_HexWidth = m_bytesPerLine * m_columnWidth + m_margin * 3 / 2;
m_textWidth = m_bytesPerLine * m_charWidth + m_margin;
int lineWidth = m_margin + + m_labelWidth + m_HexWidth + m_textWidth;
horizontalScrollBar()->setRange(0, lineWidth - viewport()->width());
horizontalScrollBar()->setPageStep(viewport()->width());
verticalScrollBar()->setRange(0, m_numLines - m_numVisibleLines + 1);
verticalScrollBar()->setPageStep(m_numVisibleLines);
ensureSelectVisible();
// qDebug() << "HexWidget::" << __func__ << "() out";
}
void HexWidget::ensureSelectVisible()
{
int xOffset = horizontalScrollBar()->value();
int xStart = m_margin + m_labelWidth;
int xEnd = m_margin + m_labelWidth + m_HexWidth + m_textWidth;
if (m_selectPosition % m_bytesPerLine + m_selectSize <= m_bytesPerLine) {
// 选中内容只在一行上
xStart = m_margin + m_labelWidth + (m_selectPosition % m_bytesPerLine) * m_columnWidth;
xEnd = m_margin + m_labelWidth + m_HexWidth + (m_selectPosition % m_bytesPerLine + m_selectSize) * m_charWidth;
}
int topLine = verticalScrollBar()->value();
int lineStart = m_selectPosition / m_bytesPerLine;
int lineEnd = (m_selectPosition + m_selectSize - 1) / m_bytesPerLine + 1;
QRect cr = QRect(xStart - xOffset, (lineStart - topLine) * m_lineHeight,
xEnd - xStart, (lineEnd - lineStart) * m_lineHeight);
QWidget *v = viewport();
if (!v->rect().intersects(cr)) {
if (cr.top() < v->rect().top())
verticalScrollBar()->setValue(lineStart);
else if (cr.bottom() > v->rect().bottom())
verticalScrollBar()->setValue(lineEnd - m_numVisibleLines + 1);
if (cr.left() < v->rect().left())
horizontalScrollBar()->setValue(xStart);
else if (cr.right() > v->rect().right())
horizontalScrollBar()->setValue(xEnd - v->rect().width() + 1);
}
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。