2014-10-27 142 views
6

在這裏寫下的關於QSpinBox使用int作爲其數據類型的限制的各種問題。通常人們想要顯示更大的數字。在我的情況下,我希望能夠以十六進制顯示無符號的32位整數。這意味着我希望我的範圍是[0x0,0xFFFFFFFF]。一個普通的QSpinBox可以運行的最大值是0x7FFFFFFF。在這裏回答我自己的問題,我提出的解決方案是通過重新實現相關的顯示和驗證函數,簡單地強制int被視爲無符號整型。帶有Unsigned Int的QSpinBox用於十六進制輸入

+0

接受你的答案。 – nnb 2014-10-27 06:38:49

回答

6

結果很簡單,而且效果很好。在這裏共享以防其他人可以從中受益。它有一個32位模式和一個16位模式。

Example of HexSpinBox

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); 
    } 

}; 
+0

你的'reinterpret_cast's違反[嚴格的alasing規則](http://eel.is/c++draft/basic.lval#8)。所以代碼包含UB – yrHeTaTeJlb 2017-10-17 08:02:22

1

我想出了同樣的問題,但使用PyQt的,所以我無法避免檢查的Qt是用C引擎蓋下做的範圍內。

解決方法是使用QDoulbeSpinbox並將值強制轉換爲textFromValue中的int值。

這裏是我的代碼(這也實現了右鍵菜單更改顯示基座):

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) 
+0

有趣的「方」注意,這對'PySide'不起作用,你會得到一個'OverflowError:Python int太大而不能轉換成C long'異常 – 2016-06-01 18:50:57

0

我知道這是一個古老的答案,但來到這裏,從谷歌。這是我與pyside 1.2.4解決方案基於有所關Techniquab的解決方案,但沒有整數溢出問題:

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)) 
1

如果您不需要完整的32位,你可以做到這一點很簡單的是這樣的:

#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(); 
    } 
}; 

在表單設計器(或其他),那麼你只需設置:

  • prefix0x
  • displayIntegerBase:16
  • maximum:255(或其他)

如果您需要完整的32位,你將不得不使用鑄造的招數,或者只是使用行編輯。