- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
精简版
我有一个 QTreeView
并希望用户能够精细控制文本的外观,为他们提供富文本格式选项。我已经有了它,所以可以选择整个项目进行格式化(例如,粗体),但我需要更大的灵 active 。例如,用户必须能够突出显示项目文本的部分并将其加粗。
请注意,我正在使用 QStandardItemModel
(请参阅下面的 SSCCE)。
详细版
给整个项目加粗很简单:
itemFont = item.font()
itemFont.setBold(True)
item.setFont(itemFont)
不幸的是,我的用户需要更细粒度的控制,所以不是
Hi how are you?
他们应该能够使用鼠标只选择第一个单词并使该项目的文本显示为:
Hi how are you?
我正在考虑的两个选项是:
setIndexWidget
在我需要此功能的每个单元格中,使用 setIndexWidget
将其显示为 QTextEdit
小部件,如下所示: To set widgets on children items on QTreeView .然后我可以使用标准工具在每个单元格中进行富文本编辑。
自定义委托(delegate)
使用自定义委托(delegate)在我需要此功能的地方绘制每个项目,就像这里应用的一样: How to make item view render rich (html) text in Qt
请注意,与那个问题不同的是,我不只是问如何呈现富文本,而是如何让用户选择文本并将其呈现为细粒度的富文本。
中南合作商会
from PySide import QtGui, QtCore
import sys
class MainTree(QtGui.QMainWindow):
def __init__(self, tree, parent = None):
QtGui.QMainWindow.__init__(self)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.setCentralWidget(tree)
self.createStatusBar()
self.createBoldAction()
self.createToolbar()
def createStatusBar(self):
self.status = self.statusBar()
self.status.setSizeGripEnabled(False)
self.status.showMessage("Ready")
def createToolbar(self):
self.textToolbar = self.addToolBar("Text actions")
self.textToolbar.addAction(self.boldTextAction)
def createBoldAction(self):
self.boldTextAction = QtGui.QAction("Bold", self)
self.boldTextAction.setIcon(QtGui.QIcon("boldText.png"))
self.boldTextAction.triggered.connect(self.emboldenText)
self.boldTextAction.setStatusTip("Make selected text bold")
def emboldenText(self):
print "Make selected text bold...How do I do this?"
class SimpleTree(QtGui.QTreeView):
def __init__(self, parent = None):
QtGui.QTreeView.__init__(self)
model = QtGui.QStandardItemModel()
model.setHorizontalHeaderLabels(['Title', 'Summary'])
rootItem = model.invisibleRootItem()
item0 = [QtGui.QStandardItem('Title0'), QtGui.QStandardItem('Summary0')]
item00 = [QtGui.QStandardItem('Title00'), QtGui.QStandardItem('Summary00')]
rootItem.appendRow(item0)
item0[0].appendRow(item00)
self.setModel(model)
self.expandAll()
def main():
app = QtGui.QApplication(sys.argv)
myTree = SimpleTree()
#myTree.show()
myMainTree = MainTree(myTree)
myMainTree.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
最佳答案
唯一合理的方法是使用选项 2:创建自定义委托(delegate)。您的情况几乎就是委托(delegate)的确切类型:使用 createEditor
创建自定义编辑器(例如旋转框或富文本编辑器等),并实现 paint
方法,可让您准确控制数据输入后的外观。虽然可能有其他方法可以做到这一点,但几乎可以肯定它们比使用委托(delegate)更糟糕。
因此,要使其正常工作,您需要为 QStyledItemDelegate
重新实现 paint
和 createEditor
。
不幸的是,为了实现createEditor
,Qt 没有提供原生的富文本行编辑器(也就是说,没有像QLineEdit
那样的富文本编辑器)。幸运的是,Mark Summerfield 实际上在他关于 PyQt 的书的第 13 章中编写了这样一个函数,因此我将其应用到下面的一个完整的示例中,其中包括主窗口中的 TreeView ,能够使用以下命令切换文本属性编辑器打开时的工具栏或上下文(右键单击)菜单或键盘快捷键。
相关帖子
我在以下线程中直接获得了实现其中许多功能的帮助:
图标
以下是工具栏中使用的图像:
代码
这是代码。对于大小,我深表歉意,但它包含了太多可能对那些学习代表有用的东西(正如 OP 显然是的那样),因此我决定不对其进行编辑:
import sys
from xml.sax.saxutils import escape as escape
from PySide import QtGui, QtCore
class MainTree(QtGui.QMainWindow):
def __init__(self, tree, parent = None):
QtGui.QMainWindow.__init__(self)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.setCentralWidget(tree)
self.createStatusBar()
self.createActions()
self.createToolbar()
self.tree = tree
self.setGeometry(500,150,400,300)
def createStatusBar(self):
self.status = self.statusBar()
self.status.setSizeGripEnabled(False)
self.status.showMessage("Ready")
def createActions(self):
'''Create all actions to be used in toolbars/menus: calls createAction()'''
self.boldTextAction = self.createAction("&Bold",
shortcut = QtGui.QKeySequence.Bold, iconName = "boldText", tip = "Embolden",
status = "Toggle bold", disabled = True)
self.italicTextAction = self.createAction("&Italic",
shortcut = QtGui.QKeySequence.Italic, iconName = "italicText", tip = "Italicize",
status = "Toggle italics", disabled = True)
self.underlineTextAction = self.createAction("&Underline",
shortcut = QtGui.QKeySequence.Underline, iconName = "underlineText", tip = "Underline",
status = "Toggle underline", disabled = True)
self.strikeoutTextAction = self.createAction("Stri&keout",
shortcut = QtGui.QKeySequence("Ctrl+K"), iconName = "strikeoutText", tip = "Strikeout",
status = "Toggle strikeout", disabled = True)
def createAction(self, text, slot = None, shortcut = None, iconName = None,
tip = None, status = None, disabled = False):
'''Creates each individual action'''
action = QtGui.QAction(text, self)
if iconName is not None:
action.setIcon(QtGui.QIcon("{0}.png".format(iconName)))
if shortcut is not None:
action.setShortcut(shortcut)
if tip is not None:
action.setToolTip(tip)
if status is not None:
action.setStatusTip(status)
if slot is not None:
action.triggered.connect(slot)
if disabled:
action.setDisabled(True)
return action
def createToolbar(self):
self.textToolbar = self.addToolBar("Text actions")
self.textToolbar.addAction(self.boldTextAction)
self.textToolbar.addAction(self.underlineTextAction)
self.textToolbar.addAction(self.italicTextAction)
self.textToolbar.addAction(self.strikeoutTextAction)
class HtmlTree(QtGui.QTreeView):
def __init__(self, parent = None):
QtGui.QTreeView.__init__(self)
model = QtGui.QStandardItemModel()
model.setHorizontalHeaderLabels(['Task', 'Description'])
self.rootItem = model.invisibleRootItem()
item0 = [QtGui.QStandardItem('Sneeze'), QtGui.QStandardItem('You have been blocked up')]
item00 = [QtGui.QStandardItem('Tickle nose'), QtGui.QStandardItem('Key first step')]
item1 = [QtGui.QStandardItem('Get a job'), QtGui.QStandardItem('Do not blow it')]
item01 = [QtGui.QStandardItem('Call temp agency'), QtGui.QStandardItem('Maybe they will be kind')]
self.rootItem.appendRow(item0)
item0[0].appendRow(item00)
self.rootItem.appendRow(item1)
item1[0].appendRow(item01)
self.setModel(model)
self.expandAll()
self.setItemDelegate(HtmlPainter(self))
self.resizeColumnToContents(0)
self.resizeColumnToContents(1)
#print "unoiform row heights? ", self.uniformRowHeights()
class HtmlPainter(QtGui.QStyledItemDelegate):
def __init__(self, parent=None):
print "delegate parent: ", parent, parent.metaObject().className()
QtGui.QStyledItemDelegate.__init__(self, parent)
def paint(self, painter, option, index):
if index.column() == 1 or index.column() == 0:
text = index.model().data(index)
palette = QtGui.QApplication.palette()
document = QtGui.QTextDocument()
document.setDefaultFont(option.font)
#Set text (color depends on whether selected)
if option.state & QtGui.QStyle.State_Selected:
displayString = "<font color={0}>{1}</font>".format(palette.highlightedText().color().name(), text)
document.setHtml(displayString)
else:
document.setHtml(text)
#Set background color
bgColor = palette.highlight().color() if (option.state & QtGui.QStyle.State_Selected)\
else palette.base().color()
painter.save()
painter.fillRect(option.rect, bgColor)
document.setTextWidth(option.rect.width())
offset_y = (option.rect.height() - document.size().height())/2
painter.translate(option.rect.x(), option.rect.y() + offset_y)
document.drawContents(painter)
painter.restore()
else:
QtGui.QStyledItemDelegate.paint(self, painter, option, index)
def sizeHint(self, option, index):
rowHeight = 18
text = index.model().data(index)
document = QtGui.QTextDocument()
document.setDefaultFont(option.font)
document.setHtml(text)
return QtCore.QSize(document.idealWidth() + 5, rowHeight) #fm.height())
def createEditor(self, parent, option, index):
if index.column() == 1:
editor = RichTextLineEdit(option, parent)
editor.returnPressed.connect(self.commitAndCloseEditor)
editor.mainWindow = parent.window()
self.setConnections(editor.mainWindow, editor)
self.enableActions(editor.mainWindow)
return editor
else:
return QtGui.QStyledItemDelegate.createEditor(self, parent, option,
index)
def setConnections(self, mainWindow, editor):
'''Create connections for font toggle actions when editor is created'''
mainWindow.boldTextAction.triggered.connect(editor.toggleBold)
mainWindow.underlineTextAction.triggered.connect(editor.toggleUnderline)
mainWindow.italicTextAction.triggered.connect(editor.toggleItalic)
mainWindow.strikeoutTextAction.triggered.connect(editor.toggleStrikeout)
def enableActions(self, mainWindow):
mainWindow.boldTextAction.setEnabled(True)
mainWindow.underlineTextAction.setEnabled(True)
mainWindow.italicTextAction.setEnabled(True)
mainWindow.strikeoutTextAction.setEnabled(True)
def disableActions(self, mainWindow):
mainWindow.boldTextAction.setDisabled(True)
mainWindow.underlineTextAction.setDisabled(True)
mainWindow.italicTextAction.setDisabled(True)
mainWindow.strikeoutTextAction.setDisabled(True)
def commitAndCloseEditor(self):
editor = self.sender()
if isinstance(editor, (QtGui.QTextEdit, QtGui.QLineEdit)):
self.commitData.emit(editor)
self.closeEditor.emit(editor, QtGui.QAbstractItemDelegate.NoHint)
def setModelData(self, editor, model, index):
if index.column() == 1:
self.disableActions(editor.mainWindow)
model.setData(index, editor.toSimpleHtml())
else:
QtGui.QStyledItemDelegate.setModelData(self, editor, model, index)
class RichTextLineEdit(QtGui.QTextEdit):
'''Single line editor invoked by delegate'''
(Bold, Italic, Underline, StrikeOut) = range(4)
returnPressed = QtCore.Signal()
def __init__(self, option, parent=None):
QtGui.QTextEdit.__init__(self, parent)
self.setLineWrapMode(QtGui.QTextEdit.NoWrap)
self.setTabChangesFocus(True)
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
#Following lines set it so text is centered in editor
fontMetrics = QtGui.QFontMetrics(self.font())
margin = 2
self.document().setDocumentMargin(margin)
height = fontMetrics.height() + (margin + self.frameWidth()) * 2
self.setFixedHeight(height)
self.setToolTip("Right click for text effect menu.")
def toggleBold(self):
self.setFontWeight(QtGui.QFont.Normal
if self.fontWeight() > QtGui.QFont.Normal else QtGui.QFont.Bold)
def toggleItalic(self):
self.setFontItalic(not self.fontItalic())
def toggleUnderline(self):
self.setFontUnderline(not self.fontUnderline())
def toggleStrikeout(self):
#Adapted from: https://www.binpress.com/tutorial/developing-a-pyqt-text-editor-part-2/145
#https://srinikom.github.io/pyside-docs/PySide/QtGui/QTextCharFormat.html
# Grab the text's format
textFormat = self.currentCharFormat()
# Change the fontStrikeOut property to its opposite
textFormat.setFontStrikeOut(not textFormat.fontStrikeOut())
# Apply the new format
self.setCurrentCharFormat(textFormat)
def contextMenuEvent(self, event):
'''
Context menu for controlling text
'''
textFormat = self.currentCharFormat()
menu = QtGui.QMenu("Text Effects")
for text, shortcut, data, checked in (
("&Bold", "Ctrl+B", RichTextLineEdit.Bold,
self.fontWeight() > QtGui.QFont.Normal),
("&Italic", "Ctrl+I", RichTextLineEdit.Italic,
self.fontItalic()),
("Stri&keout", "Ctrl+K", RichTextLineEdit.StrikeOut,
textFormat.fontStrikeOut()),
("&Underline", "Ctrl+U", RichTextLineEdit.Underline,
self.fontUnderline())):
action = menu.addAction(text, self.setTextEffect)
if shortcut is not None:
action.setShortcut(QtGui.QKeySequence(shortcut))
action.setData(data)
action.setCheckable(True)
action.setChecked(checked)
self.ensureCursorVisible()
menu.exec_(self.viewport().mapToGlobal(
self.cursorRect().center()))
def setTextEffect(self):
'''Called by context menu'''
action = self.sender()
if action is not None and isinstance(action, QtGui.QAction):
what = int(action.data())
if what == RichTextLineEdit.Bold:
self.toggleBold()
return
if what == RichTextLineEdit.Italic:
self.toggleItalic()
return
if what == RichTextLineEdit.Underline:
self.toggleUnderline()
return
format = self.currentCharFormat()
if what == RichTextLineEdit.StrikeOut:
format.setFontStrikeOut(not format.fontStrikeOut())
self.mergeCurrentCharFormat(format)
def keyPressEvent(self, event):
'''
Handles all keyboard shortcuts, and stops retun from returning newline
'''
if event.modifiers() & QtCore.Qt.ControlModifier:
handled = False
if event.key() == QtCore.Qt.Key_B:
self.toggleBold()
handled = True
elif event.key() == QtCore.Qt.Key_I:
self.toggleItalic()
handled = True
elif event.key() == QtCore.Qt.Key_U:
self.toggleUnderline()
handled = True
if handled:
event.accept()
return
if event.key() in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return):
self.returnPressed.emit()
event.accept()
else:
QtGui.QTextEdit.keyPressEvent(self, event)
def toSimpleHtml(self):
html = ""
block = self.document().begin()
while block.isValid():
iterator = block.begin()
while iterator != block.end():
fragment = iterator.fragment()
if fragment.isValid():
format = fragment.charFormat()
text = escape(fragment.text())
if format.fontUnderline():
text = "<u>{}</u>".format(text)
if format.fontItalic():
text = "<i>{}</i>".format(text)
if format.fontWeight() > QtGui.QFont.Normal:
text = "<b>{}</b>".format(text)
if format.fontStrikeOut():
text = "<s>{}</s>".format(text)
html += text
iterator += 1
block = block.next()
return html
def main():
app = QtGui.QApplication(sys.argv)
myTree = HtmlTree() #myTree.show()
myMainTree = MainTree(myTree)
myMainTree.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
关于qt - 如何在 View (PyQt/PySide/Qt)中实现富文本编辑器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32773679/
我正在使用 Qt 语言学家翻译一个 ui 文件。我使用 lupdate 获取了它的 ts 文件,并翻译了这些单词和短语。现在我想将它添加到我的代码中,但我从它的教程中发现我似乎必须将 tr() 添加到
我想在 Qt Creator 中创建下面的简单控制台应用程序: #include int main(int argc, char* argv[]) { std::cout #include
我想将 libQtGui.so.4 libQtNetwork.so.4 和 libQtCore.so.4 包含在与我的应用程序所在的目录相同的目录中。我如何让 Qt 理解这一点? y 目的是拥有一个使
我有一个充满 QPushButtons 和 QLabels 以及各种其他有趣的 QWidget 的窗口,所有这些都使用各种 QLayout 对象动态布局...而我想做的是偶尔制作一些这些小部件变得不可
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎与 help center 中定义的范围内的编程无关。 . 关闭 7 年前。 Improve
我想知道 Qt 是否将下面代码的“版本 1”之类的东西放在堆上?在版本 1 中,Qt 会将 dirStuff 放在堆栈上还是堆上?我问是因为我有一种感觉,Java 将所有数据结构放在堆上......不
这个问题是关于 Qt Installer Framework 2.0 版的。 在这一点上,使用 Qt 安装程序框架的人都知道,如果不进行自定义,您根本无法通过安装程序覆盖现有安装。这样做显然是为了解决
关闭。这个问题是off-topic .它目前不接受答案。 想改善这个问题吗? Update the question所以它是 on-topic对于堆栈溢出。 8年前关闭。 Improve this q
因为我在我的计算机上安装了 Qt 4.8.4 和 Qt 5.1,所以我遇到了问题。 当只有 Qt 4.8.4 存在时,一切都很好。 当我添加 Qt 5.1 时,这个工作正常,但 Qt 4.8.4 给了
我无法在我的 Ubuntu 12 中安装更多软件包。我尝试了 apt-get install -f ,以及许多其他类似的技巧,但在找到解决方案方面没有进展。 这是属于 Qt 的损坏包: 以下包具有未满
我正在尝试使用 Virtual Box 中的 Ubuntu 机器复制我们目前在物理 Ubuntu 服务器上运行的应用程序。它是一个 QT 应用程序,但在服务器上我们使用 NPM 的 pm2 运行它。安
问题: Qt Creator 是用 Qt Creator 构建的吗? 同样,Qt Designer 是用 Qt Designer 构建的吗? 顺便说一句,为什么有两个 Qt IDE?他们是竞争对手吗?
当我使用 QWidget设计用户界面时,我总是对它的大小属性有点困惑。有size policy , geometry和 hintSize . 我只知道size policy之间的关系和 hintSiz
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我想知道是否有一种很好的方法可以让用户像 LabView 一样创建节点图(有限制)。 像这样的东西: 我见过http://www.pyqtgraph.org/ ,这似乎有类似的东西,我确实打算使用 P
在 Qt 中是否有一种跨平台的方式来获得用户喜欢的固定宽度和比例字体? 例如,在 cocoa 中,有 NSFont *proportional = [NSFont userFontOfSize:12.
我想使用 Qt 和 C++ 制作这样的交互式图表:http://jsxgraph.uni-bayreuth.de/wiki/index.php/Cubic_spline_interpolation 关
我正在编写一个嵌入式设备屏幕的模拟(其中包含主 QWidget 顶部的自定义小部件),虽然屏幕的原始尺寸是 800x600,但我希望能够按比例放大和缩小它拖动窗口的角。如果不使用网格布局和担架(不会向
在下面的示例中,我是否必须从堆中删除对象?如果是的话,怎么办? #include #include #include #include #include int main(int argc,
来自 Web 开发背景,我现在进入 QT 应用程序开发。 使用 QFonts 我已经看到我显然只有两个选择,在 QT 中定义字体大小;按像素大小或点大小。 在制作网页布局时,我习惯于以相对方式定义所有
我是一名优秀的程序员,十分优秀!