如何通过对话框重绘PySide冰箱磁贴部件并修改其颜色
嘿,作为PySide新手能折腾到冰箱磁贴这个程度已经超棒啦!我来帮你搞定修改所有磁贴颜色并重绘的问题,咱们一步步来:
核心思路
要实现这个功能,咱们需要解决三个关键问题:
- 让每个磁贴能存储自己的颜色(而不是硬编码的蓝色)
- 给对话框加颜色选择控件,让用户能选想要的颜色
- 主窗口能管理所有磁贴,收到新颜色后通知所有磁贴更新并重绘
修改后的完整代码
下面是修改好的代码,关键部分我都加了注释:
from PySide import QtCore, QtGui import fridgemagnets_rc class PropertyChangeWindow(QtGui.QDialog): """属性修改窗口""" # 定义信号,用来传递选中的颜色给主窗口 color_selected = QtCore.Signal(QtGui.QColor) def __init__(self, magnet_text, parent=None): super(PropertyChangeWindow, self).__init__(parent) self.block = magnet_text self.setWindowTitle("Properties of " + magnet_text) self.setMinimumSize(160, 160) # 添加颜色选择按钮,让用户能挑选颜色 self.color_btn = QtGui.QPushButton("选择磁贴颜色") self.color_btn.clicked.connect(self.select_color) self.selected_color = QtGui.QColor(QtCore.Qt.blue) # 默认初始颜色为蓝色 buttonBox = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel) buttonBox.accepted.connect(self.accept) buttonBox.rejected.connect(self.reject) mainLayout = QtGui.QVBoxLayout() mainLayout.addWidget(self.color_btn) mainLayout.addWidget(buttonBox) self.setLayout(mainLayout) def select_color(self): # 弹出系统颜色选择对话框,让用户选颜色 color = QtGui.QColorDialog.getColor(self.selected_color, self, "选择磁贴颜色") if color.isValid(): self.selected_color = color # 更新按钮背景色,让用户直观看到选中的颜色 palette = self.color_btn.palette() palette.setColor(QtGui.QPalette.Button, color) self.color_btn.setPalette(palette) def accept(self): # 发射选中的颜色信号,通知主窗口更新所有磁贴 self.color_selected.emit(self.selected_color) super(PropertyChangeWindow, self).accept() # 关闭对话框 class DragLabel(QtGui.QLabel): def __init__(self, text, parent): super(DragLabel, self).__init__(parent) self.text = text self._color = QtCore.Qt.blue # 新增:存储磁贴的颜色属性 self._update_pixmap() # 抽出生成图片的逻辑到单独方法,方便后续更新 def _update_pixmap(self): # 生成磁贴图片的逻辑,抽出来方便修改颜色后重新调用 metric = QtGui.QFontMetrics(self.font()) size = metric.size(QtCore.Qt.TextSingleLine, self.text) image = QtGui.QImage(size.width() + 12, size.height() + 12, QtGui.QImage.Format_ARGB32_Premultiplied) image.fill(QtGui.qRgba(0, 0, 0, 0)) font = QtGui.QFont() font.setStyleStrategy(QtGui.QFont.ForceOutline) painter = QtGui.QPainter() painter.begin(image) painter.setRenderHint(QtGui.QPainter.Antialiasing) painter.setBrush(self._color) # 使用存储的颜色,不再是硬编码的蓝色 painter.drawRoundedRect(QtCore.QRectF(0.1, 0.1, image.width()-1, image.height()-1), 25, 25, QtCore.Qt.RelativeSize) painter.setFont(font) painter.setBrush(QtCore.Qt.black) painter.drawText(QtCore.QRect(QtCore.QPoint(6, 6), size), QtCore.Qt.AlignCenter, self.text) painter.end() self.setPixmap(QtGui.QPixmap.fromImage(image)) self.labelText = text def set_color(self, color): # 新增:更新磁贴颜色并重绘的方法 self._color = color self._update_pixmap() # 重新生成图片 self.update() # 触发控件重绘 def mousePressEvent(self, event): itemData = QtCore.QByteArray() dataStream = QtCore.QDataStream(itemData, QtCore.QIODevice.WriteOnly) dataStream << QtCore.QByteArray(str(self.labelText)) << QtCore.QPoint(event.pos() - self.rect().topLeft()) mimeData = QtCore.QMimeData() mimeData.setData('application/x-fridgemagnet', itemData) mimeData.setText(self.labelText) drag = QtGui.QDrag(self) drag.setMimeData(mimeData) drag.setHotSpot(event.pos() - self.rect().topLeft()) drag.setPixmap(self.pixmap()) self.hide() if drag.exec_(QtCore.Qt.MoveAction | QtCore.Qt.CopyAction, QtCore.Qt.CopyAction) == QtCore.Qt.MoveAction: self.close() else: self.show() def mouseReleaseEvent(self, event): # 修复原代码中未定义_clickevent的问题,暂时注释掉无用逻辑 pass def mouseDoubleClickEvent(self, event): self.new_window = PropertyChangeWindow(self.text, self.parent()) # 连接对话框的颜色选中信号到主窗口的更新方法 self.new_window.color_selected.connect(self.parent().update_all_magnets_color) self.new_window.show() class DragWidget(QtGui.QWidget): def __init__(self, parent=None): super(DragWidget, self).__init__(parent) self.magnets = [] # 新增:存储所有磁贴的列表,方便统一管理 dictionaryFile = QtCore.QFile(':/dictionary/words.txt') dictionaryFile.open(QtCore.QFile.ReadOnly) x = 5 y = 5 for word in QtCore.QTextStream(dictionaryFile).readAll().split(): wordLabel = DragLabel(word, self) wordLabel.move(x, y) wordLabel.show() self.magnets.append(wordLabel) # 将每个初始磁贴添加到列表中 x += wordLabel.width() + 2 if x >= 245: x = 5 y += wordLabel.height() + 2 newPalette = self.palette() newPalette.setColor(QtGui.QPalette.Window, QtCore.Qt.white) self.setPalette(newPalette) self.setMinimumSize(400, max(200, y)) self.setWindowTitle("Fridge Magnets") self.setAcceptDrops(True) def update_all_magnets_color(self, color): # 新增:遍历所有磁贴,更新它们的颜色 for magnet in self.magnets: magnet.set_color(color) self.update() # 触发窗口整体重绘 def dragEnterEvent(self, event): if event.mimeData().hasFormat('application/x-fridgemagnet'): if event.source() in self.children(): event.setDropAction(QtCore.Qt.MoveAction) event.accept() else: event.acceptProposedAction() elif event.mimeData().hasText(): event.acceptProposedAction() else: event.ignore() dragMoveEvent = dragEnterEvent def dropEvent(self, event): if event.mimeData().hasFormat('application/x-fridgemagnet'): mime = event.mimeData() itemData = mime.data('application/x-fridgemagnet') dataStream = QtCore.QDataStream(itemData, QtCore.QIODevice.ReadOnly) text = QtCore.QByteArray() offset = QtCore.QPoint() dataStream >> text >> offset try: # Python v3. text = str(text, encoding='latin1') except TypeError: # Python v2. text = str(text) newLabel = DragLabel(text, self) newLabel.move(event.pos() - offset) newLabel.show() self.magnets.append(newLabel) # 拖放生成的新磁贴也要加入列表 if event.source() in self.children(): event.setDropAction(QtCore.Qt.MoveAction) event.accept() else: event.acceptProposedAction() elif event.mimeData().hasText(): pieces = event.mimeData().text().split() position = event.pos() for piece in pieces: newLabel = DragLabel(piece, self) newLabel.move(position) newLabel.show() self.magnets.append(newLabel) # 文本拖放生成的磁贴也加入列表 position += QtCore.QPoint(newLabel.width(), 0) event.acceptProposedAction() else: event.ignore() if __name__ == '__main__': import sys app = QtGui.QApplication(sys.argv) window = DragWidget() window.show() sys.exit(app.exec_())
关键改动说明
给DragLabel添加颜色属性和更新方法:
- 新增
_color属性存储磁贴颜色,默认蓝色 - 把生成图片的逻辑抽成
_update_pixmap方法,方便修改颜色后重新生成 - 新增
set_color方法,用来更新颜色并触发重绘
- 新增
升级PropertyChangeWindow对话框:
- 添加颜色选择按钮,点击弹出系统颜色选择器
- 定义
color_selected信号,用来把选中的颜色传递给主窗口 - 确认对话框时发射信号,通知主窗口更新所有磁贴
DragWidget管理所有磁贴:
- 新增
magnets列表存储所有磁贴(包括初始生成和拖放新增的) - 新增
update_all_magnets_color方法,遍历所有磁贴调用set_color更新颜色
- 新增
修复原代码的小问题:
- 注释掉了
mouseReleaseEvent中未定义的_clickevent逻辑,避免运行报错 - 拖放生成新磁贴时,也把它们加入
magnets列表,确保新磁贴也能被统一修改颜色
- 注释掉了
现在你运行代码,双击任意磁贴打开对话框,选择颜色后点击确定,所有磁贴就会变成你选的颜色啦!
内容的提问来源于stack exchange,提问作者codingtoddler
相关产品推荐
相关产品推荐

