I ran into the same problem, but using PyQt, so I could not avoid the range check that Qt did in C under the hood.
The workaround was to use QDoulbeSpinbox and pass the int value to textFromValue.
Here is my code (it also implements a right-click menu to change the display base):
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 "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)