我有以下pyqt代码,用于显示数据网格。
我能够单击一个字母,打开一个文本输入框,并将数据成功保存到网格中,并在终端中打印更新的数据。
我尝试了update()
和repaint()
,但是它们什么也没做,调用createLayout()
方法会抛出QLayout: Attempting to add QLayout "" to Widget "", which already has a layout
的错误
如何刷新网格/窗口小部件/布局以显示新数据?
from PyQt5 import QtWidgets, QtCore, QtGui
import string
grid = [[["text", "GREEN"], 0, ["text", "RED"], 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0]]
BTN = """QPushButton{{font-weight: bold; color: {};
font-size: 14px; background-color: {};
border-width: 2px; border-radius: 100px}}"""
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self.letter_count = dict(zip(string.ascii_uppercase, [x for x in range(26)]))
self.initUI()
self.createLayout()
self.center_widget()
def initUI(self):
p = self.palette()
gradient = QtGui.QLinearGradient(0, 0, 0, 400)
gradient.setColorAt(0.0, QtGui.QColor('#f1f1f1'))
gradient.setColorAt(1.0, QtGui.QColor('#00a1de'))
p.setBrush(QtGui.QPalette.Window, QtGui.QBrush(gradient))
self.setPalette(p)
def createLayout(self):
hlay = QtWidgets.QHBoxLayout(self)
frameL = QtWidgets.QFrame()
vlay = QtWidgets.QVBoxLayout(frameL)
frame = QtWidgets.QFrame()
frame.setObjectName("principal")
frame.setStyleSheet("#principal{border: 2px solid white;}")
hlay.addWidget(frameL)
hlay.addWidget(frame)
gridLayout = QtWidgets.QGridLayout(frame)
h = 60 # height
for i, row in enumerate(grid):
letter = "{}".format(string.ascii_uppercase[i])
frameButton = QtWidgets.QFrame()
frameButton.setFixedHeight(h)
frameButton.setContentsMargins(0, 0, 0, 0)
lay = QtWidgets.QVBoxLayout(frameButton)
button = QtWidgets.QPushButton(letter)
button.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
button.clicked.connect(lambda x, letter=letter: self.populate_row(letter)) # Every button click returns 'J'
lay.addWidget(button)
vlay.addWidget(frameButton)
for j, val in enumerate(row):
gridButton = QtWidgets.QPushButton()
gridButton.setFixedSize(h, h)
if isinstance(val, list):
gridButton.setText(val[0])
if val[1] == "GREEN":
gridButton.setStyleSheet(BTN.format('white', 'green'))
elif val[1] == "RED":
gridButton.setStyleSheet(BTN.format('white', 'red'))
else:
gridButton.setStyleSheet(BTN.format('black', 'white'))
gridButton.setText("{}".format(val))
gridLayout.addWidget(gridButton, i, j)
for ix in range(j + 1):
label = QtWidgets.QLabel("{}".format(ix + 1))
label.setAlignment(QtCore.Qt.AlignCenter)
gridLayout.addWidget(label, i + 1, ix)
vlay.addWidget(QtWidgets.QLabel())
def center_widget(self):
self.window().setGeometry(
QtWidgets.QStyle.alignedRect(
QtCore.Qt.LeftToRight,
QtCore.Qt.AlignCenter,
self.window().size(),
QtWidgets.QApplication.desktop().availableGeometry())
)
def populate_row(self, letter):
""" Populate the row from index 0 - end """
print(letter)
self.wi = QtWidgets.QWidget()
self.wi.resize(660, 360)
textBox = QtWidgets.QPlainTextEdit(self.wi)
Rbtn = QtWidgets.QPushButton('Add To Row')
Rbtn.clicked.connect(lambda: self.input_to_grid(textBox.toPlainText(), letter))
layout = QtWidgets.QVBoxLayout()
layout.addWidget(textBox)
layout.addWidget(Rbtn)
Rbtn.move(600, 300)
self.wi.setLayout(layout)
self.wi.show()
return self.wi
def input_to_grid(self, text, letter):
print(text, letter)
lst = text.split(' ')
for i, x in enumerate(lst):
self.add_to_grid((letter, i + 1), x)
print((letter, i + 1), x)
self.print_grid()
def add_to_grid(self, loc, item):
x, y = self.translate(loc)
grid[x][y] = [item]
def translate(self, loc):
for k, v in self.letter_count.items():
if loc[0].upper() == k:
x = v
y = int(loc[1]) - 1
return x, y
def print_grid(self):
""" Print the grid prettier than normal.. """
print('\n'.join(['\t'.join([str(c) for c in r]) for r in grid]))
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
答案 0 :(得分:1)
由于浪费时间和内存,替换布局或小部件是一个坏主意,正确的事情是重用,在这种情况下,我将创建一个映射按钮的列表列表,因此当您要更新一些按钮时网格中的数据,数据将在按钮中更新。
from PyQt5 import QtWidgets, QtCore, QtGui
import string
grid = [[["text", "GREEN"], 0, ["text", "RED"], 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0]]
BTN = """QPushButton{{font-weight: bold; color: {};
font-size: 14px; background-color: {};
border-width: 2px; border-radius: 100px}}"""
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self.letter_count = dict(zip(string.ascii_uppercase, [x for x in range(26)]))
self.initUI()
self.buttons = []
self.createLayout()
self.center_widget()
def initUI(self):
p = self.palette()
gradient = QtGui.QLinearGradient(0, 0, 0, 400)
gradient.setColorAt(0.0, QtGui.QColor('#f1f1f1'))
gradient.setColorAt(1.0, QtGui.QColor('#00a1de'))
p.setBrush(QtGui.QPalette.Window, QtGui.QBrush(gradient))
self.setPalette(p)
def createLayout(self):
hlay = QtWidgets.QHBoxLayout(self)
frameL = QtWidgets.QFrame()
vlay = QtWidgets.QVBoxLayout(frameL)
frame = QtWidgets.QFrame()
frame.setObjectName("principal")
frame.setStyleSheet("#principal{border: 2px solid white;}")
hlay.addWidget(frameL)
hlay.addWidget(frame)
self.gridLayout = QtWidgets.QGridLayout(frame)
h = 60 # height
for i, row in enumerate(grid):
letter = "{}".format(string.ascii_uppercase[i])
frameButton = QtWidgets.QFrame()
frameButton.setFixedHeight(h)
frameButton.setContentsMargins(0, 0, 0, 0)
lay = QtWidgets.QVBoxLayout(frameButton)
button = QtWidgets.QPushButton(letter)
button.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
button.clicked.connect(lambda x, letter=letter: self.populate_row(letter)) # Every button click returns 'J'
lay.addWidget(button)
vlay.addWidget(frameButton)
self.buttons.append([])
for j, val in enumerate(row):
gridButton = QtWidgets.QPushButton()
gridButton.setFixedSize(h, h)
self.buttons[i].append(gridButton)
self.gridLayout.addWidget(gridButton, i, j)
for ix in range(j + 1):
label = QtWidgets.QLabel("{}".format(ix + 1))
label.setAlignment(QtCore.Qt.AlignCenter)
self.gridLayout.addWidget(label, i + 1, ix)
vlay.addWidget(QtWidgets.QLabel())
self.update_data()
def update_data(self):
for i, row in enumerate(grid):
for j, val in enumerate(row):
btn = self.buttons[i][j]
if isinstance(val, list):
btn.setText(val[0])
if val[1] == "GREEN":
btn.setStyleSheet(BTN.format('white', 'green'))
elif val[1] == "RED":
btn.setStyleSheet(BTN.format('white', 'red'))
else:
btn.setStyleSheet(BTN.format('black', 'white'))
btn.setText("{}".format(val))
def center_widget(self):
self.window().setGeometry(
QtWidgets.QStyle.alignedRect(
QtCore.Qt.LeftToRight,
QtCore.Qt.AlignCenter,
self.window().size(),
QtWidgets.QApplication.desktop().availableGeometry())
)
def populate_row(self, letter):
dialog = QtWidgets.QDialog()
dialog.resize(660, 360)
textBox = QtWidgets.QPlainTextEdit(dialog)
Rbtn = QtWidgets.QPushButton('Add To Row')
Rbtn.clicked.connect(lambda: self.input_to_grid(textBox.toPlainText(), letter))
layout = QtWidgets.QVBoxLayout(dialog)
layout.addWidget(textBox)
layout.addWidget(Rbtn)
dialog.exec_()
def input_to_grid(self, text, letter):
print(text, letter)
lst = text.split(' ')
for i, x in enumerate(lst):
self.add_to_grid((letter, i + 1), x)
print((letter, i + 1), x)
self.print_grid()
self.update_data()
def add_to_grid(self, loc, item):
x, y = self.translate(loc)
grid[x][y] = item
def translate(self, loc):
for k, v in self.letter_count.items():
if loc[0].upper() == k:
x = v
y = int(loc[1]) - 1
return x, y
def print_grid(self):
""" Print the grid prettier than normal.. """
print('\n'.join(['\t'.join([str(c) for c in r]) for r in grid]))
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())