Có rất nhiều câu hỏi được viết ở đây về giới hạn của QSpinBox khi sử dụng int làm kiểu dữ liệu của nó. Thường thì mọi người muốn hiển thị số lớn hơn. Trong trường hợp của tôi, tôi muốn có thể hiển thị một số nguyên 32 bit chưa ký trong hệ thập lục phân. Điều này có nghĩa là tôi muốn phạm vi của tôi là [0x0, 0xFFFFFFFF]. QSpinBox bình thường lớn nhất có thể là 0x7FFFFFFF. Trả lời câu hỏi của riêng tôi ở đây, giải pháp mà tôi đưa ra là chỉ cần buộc int được xử lý như một int không dấu, bằng cách thực hiện lại các chức năng hiển thị và xác nhận có liên quan.QSpinBox với Unsigned Int cho đầu vào Hex
Trả lời
Kết quả khá đơn giản và hoạt động tốt. Chia sẻ ở đây trong trường hợp bất kỳ ai khác có thể hưởng lợi từ việc này. Nó có chế độ 32 bit và chế độ 16 bit.
class HexSpinBox : public QSpinBox
{
public:
HexSpinBox(bool only16Bits, QWidget *parent = 0) : QSpinBox(parent), m_only16Bits(only16Bits)
{
setPrefix("0x");
setDisplayIntegerBase(16);
if (only16Bits)
setRange(0, 0xFFFF);
else
setRange(INT_MIN, INT_MAX);
}
unsigned int hexValue() const
{
return u(value());
}
void setHexValue(unsigned int value)
{
setValue(i(value));
}
protected:
QString textFromValue(int value) const
{
return QString::number(u(value), 16).toUpper();
}
int valueFromText(const QString &text) const
{
return i(text.toUInt(0, 16));
}
QValidator::State validate(QString &input, int &pos) const
{
QString copy(input);
if (copy.startsWith("0x"))
copy.remove(0, 2);
pos -= copy.size() - copy.trimmed().size();
copy = copy.trimmed();
if (copy.isEmpty())
return QValidator::Intermediate;
input = QString("0x") + copy.toUpper();
bool okay;
unsigned int val = copy.toUInt(&okay, 16);
if (!okay || (m_only16Bits && val > 0xFFFF))
return QValidator::Invalid;
return QValidator::Acceptable;
}
private:
bool m_only16Bits;
inline unsigned int u(int i) const
{
return *reinterpret_cast<unsigned int *>(&i);
}
inline int i(unsigned int u) const
{
return *reinterpret_cast<int *>(&u);
}
};
'reinterpret_cast's vi phạm [quy tắc theo đuổi nghiêm ngặt] (http://eel.is/c++draft/basic.lval#8). Vì vậy, mã có chứa UB – yrHeTaTeJlb
tôi đã đưa ra vấn đề tương tự nhưng sử dụng PyQt vì vậy tôi không thể tránh phạm vi kiểm tra rằng Qt đang làm trong C dưới mui xe.
Cách giải quyết là sử dụng QDoulbeSpinbox và để truyền giá trị thành int trong textFromValue.
Đây là mã của tôi (nó cũng thực hiện một menu chuột phải để thay đổi cơ sở hiển thị):
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from future_builtins import *
import re
import sys
from PyQt4.QtCore import (QRegExp, Qt)
from PyQt4.QtGui import (QApplication, QRegExpValidator, QDoubleSpinBox)
from PyQt4.QtCore import pyqtSlot,SIGNAL,SLOT
from PyQt4 import QtCore, QtGui
# Regex adapted from Mark Pilgrim's "Dive Into Python" book
class QHexSpinBox(QDoubleSpinBox):
def __init__(self, parent=None):
super(QHexSpinBox, self).__init__(parent)
self.mode = 'dec'
self.setContextMenuPolicy(Qt.CustomContextMenu);
regex = QRegExp("[x0-9A-Fa-f]{1,8}")
regex.setCaseSensitivity(Qt.CaseInsensitive)
self.hexvalidator = QRegExpValidator(regex, self)
regex = QRegExp("[0-9]{1,10}")
regex.setCaseSensitivity(Qt.CaseInsensitive)
self.decvalidator = QRegExpValidator(regex, self)
regex = QRegExp("[b0-1]{1,64}")
regex.setCaseSensitivity(Qt.CaseInsensitive)
self.binvalidator = QRegExpValidator(regex, self)
self.setRange(1, 999999)
self.connect(self,SIGNAL("customContextMenuRequested(QPoint)"),
self,SLOT("contextMenuRequested(QPoint)"))
@pyqtSlot(QtCore.QPoint)
def contextMenuRequested(self,point):
menu = QtGui.QMenu()
hex = menu.addAction("Hex")
dec = menu.addAction("Dec")
bin = menu.addAction("Bin")
self.connect(hex,SIGNAL("triggered()"),
self,SLOT("hex()"))
self.connect(dec,SIGNAL("triggered()"),
self,SLOT("dec()"))
self.connect(bin,SIGNAL("triggered()"),
self,SLOT("bin()"))
menu.exec_(self.mapToGlobal(point))
@pyqtSlot()
def hex(self):
self.mode = 'hex'
self.setValue(self.value())
@pyqtSlot()
def dec(self):
self.mode = 'dec'
self.setValue(self.value())
@pyqtSlot()
def bin(self):
self.mode = 'bin'
self.setValue(self.value())
def validate(self, text, pos):
if self.mode == 'hex':
return self.hexvalidator.validate(text, pos)
if self.mode == 'dec':
return self.decvalidator.validate(text, pos)
if self.mode == 'bin':
return self.binvalidator.validate(text, pos)
def valueFromText(self, text):
if self.mode == 'hex':
return int(unicode(text), 16)
elif self.mode == 'dec':
return int(unicode(text))
elif self.mode == 'bin':
return int(unicode(text), 2)
def textFromValue(self, value):
value = int(value)
if self.mode == 'hex':
return hex(value)
elif self.mode == 'dec':
return str(value)
elif self.mode =='bin':
return "0b{0:b}".format(value)
Thú vị "bên" lưu ý, điều này không hoạt động trên 'PySide' bạn sẽ nhận được một' OverflowError: Python int quá lớn để chuyển đổi sang C dài' Ngoại lệ –
Tôi biết đây là một câu trả lời cũ nhưng đến đây từ google. Đây là giải pháp của tôi với pyside 1.2.4 dựa hơi tắt của giải pháp Techniquab nhưng không có vấn đề tràn số nguyên:
from PySide import QtCore, QtGui
from numpy import base_repr
from PySide.QtGui import QRegExpValidator
class QBaseSpinBox(QtGui.QAbstractSpinBox):
valueChanged = QtCore.Signal(int)
_value = 0
default_value = 0
base = 10
def __init__(self, parent=None):
self.setRange(None, None)
QtGui.QAbstractSpinBox.__init__(self, parent)
self.set_base(self.base)
self.lineEdit().setValidator(QRegExpValidator(self))
self.default_value = self.value()
self.lineEdit().textChanged.connect(self.textChanged)
self.lineEdit().setContextMenuPolicy(QtCore.Qt.CustomContextMenu);
self.lineEdit().customContextMenuRequested.connect(self.contextMenuRequested)
@QtCore.Slot()
def contextMenuRequested(self, point):
menu = self.lineEdit().createStandardContextMenu() #QtGui.QMenu()
actionDefault = menu.addAction("&Set Default Value of %s" % self.textFromValue(self.default_value),
shortcut=QtCore.Qt.CTRL | QtCore.Qt.Key_D) #QtGui.QKeySequence("Ctrl+D")))
menu.insertSeparator(actionDefault)
actionDefault.triggered.connect(self.menuActionDefault_triggered)
menu.exec_(self.mapToGlobal(point))
@QtCore.Slot()
def menuActionDefault_triggered(self):
self.setValue(self.default_value)
def value(self):
return self._value
def setValue(self, value):
if self.validate(value) == QtGui.QValidator.Invalid:
self.setValue(self._value)
return
changed = False
if self._value != value:
changed = True
self._value = value
self.lineEdit().setText(self.textFromValue(value))
if changed:
self.valueChanged.emit(self._value)
@QtCore.Slot()
def stepBy(self, value):
self.setValue(self._value + value)
QtGui.QAbstractSpinBox.stepBy(self, self._value)
def stepEnabled(self):
return QtGui.QAbstractSpinBox.StepDownEnabled | QtGui.QAbstractSpinBox.StepUpEnabled
@QtCore.Slot()
def textChanged(self, text):
try:
self.setValue(int(text, self.base))
except:
self.setValue(self._value)
def setRange(self, _min, _max):
self.minimum = _min if _min != None else 0
self.maximum = _max if _max != None else 0xFFFFFFFFFFFFFFFF
def validate(self, input):
if not input:
return QtGui.QValidator.Intermediate
try:
try:
value = int(input, self.base)
except TypeError:
value = input
if not (self.minimum <= input <= self.maximum):
raise Exception()
except Exception as ex:
return QtGui.QValidator.Invalid
return QtGui.QValidator.Acceptable
def valueFromText(self, text):
return int(text, self.base)
def textFromValue(self, value):
return base_repr(value, self.base).upper()
def set_default_value(self, value):
self.default_value = int(value)
#self.setValue(self.default_value)
self.set_base(self.base) # Redo the tooltip
def set_base(self, base):
self.base = base
min = self.textFromValue(self.minimum)
max = self.textFromValue(self.maximum)
default = self.textFromValue(self.default_value)
self.lineEdit().setToolTip("Base %d\nRange: %s-%s\nDefault Value: %s" % (self.base, min, max, default))
Nếu bạn không cần phải đầy đủ 32 bit, bạn có thể làm điều đó rất đơn giản như thế này:
#pragma once
#include <QSpinBox>
class PaddedSpinBox : public QSpinBox
{
public:
PaddedSpinBox(QWidget *parent = 0) : QSpinBox(parent)
{
}
protected:
QString textFromValue(int value) const override
{
// Pad to the width of maximum().
int width = QString::number(maximum(), displayIntegerBase()).size();
return QString("%1").arg(value, width, displayIntegerBase(), QChar('0')).toUpper();
}
};
Trong thiết kế mẫu (hoặc bất kỳ) sau đó bạn chỉ cần thiết lập:
prefix
:0x
displayIntegerBase
: 16maximum
: 255 (hoặc bất kỳ)
Nếu bạn cần đầy đủ 32 bit bạn sẽ phải sử dụng thủ thuật đúc, hoặc có thể chỉ cần sử dụng một dòng chỉnh sửa.
- 1. QValidator cho đầu vào hex
- 2. int vào chuỗi hex
- 3. unsigned đại diện hex dài
- 4. scanf char unsigned trong hex
- 5. Hãy so sánh int và unsigned int
- 6. chuyển đổi int nổi để hex
- 7. Unsigned int để unsigned long long well defined?
- 8. C - unsigned int để unsigned char mảng chuyển đổi
- 9. C++: cần cảnh báo cho: unsigned int i = -1;
- 10. lỗi: không có chức năng phù hợp cho cuộc gọi đến ‘min (dài unsigned int &, unsigned int &)’
- 11. Objective C: Unsigned int so sánh
- 12. Chuyển đổi một chuỗi hex đến một int hex
- 13. int xúc tiến để int unsigned trong C và C#
- 14. sql server 4 byte unsigned int
- 15. Python - Chuyển đổi Hex thành INT/CHAR
- 16. Java unsigned byte [2] để int?
- 17. Sự khác biệt thực sự giữa "int" và "unsigned int"
- 18. Chuyển đổi int thành hex với các số 0 hàng đầu
- 19. cách chuyển đổi ascii thành unsigned int
- 20. JNI: chuyển đổi unsigned int thành jint
- 21. 4 byte unsigned int trong SQL Server?
- 22. Khởi tạo mảng byte unsigned sử dụng hex số
- 23. Chuyển đổi từ RGB int sang Hex
- 24. Chuỗi ký tự hex để ký int trong Python 3.2?
- 25. unsigned ngắn vs unsigned int - đôi khi họ là cùng một phạm vi?
- 26. Tham chiếu không xác định đối với CryptoPP :: AlignedAllocate (unsigned int)
- 27. Là loại unsigned ngắn + int thực hiện được xác định?
- 28. C - Chuyển đổi int dài chuỗi hex ký
- 29. C dưới dạng viết tắt của unsigned long int
- 30. Mẫu <unsigned int N> có nghĩa là gì?
Chấp nhận câu trả lời của bạn. – nnb