动态创建按钮的问题。我正在写一个应用程序,我需要:
- 动态创建本质上是外部程序快捷方式的按钮。
- 如有必要,请移除所需按钮,以便其余按钮根据布局移动。
- 将配置保存到 ini 文件,以便在重新启动后保存所有创建的按钮。
现在是什么:
- 按钮是根据 Grid 布局动态创建的,可以运行附加到它们的 exe 文件,但只能运行最后附加的那个。
- 删除仅适用于最后创建的按钮,方法是用鼠标右键单击它。
- 事实证明,将按钮配置保存到 settings.ini 文件 - 但程序启动时我无法提取数据。
如果有人有任何想法,我将不胜感激。我附上了一个最小的工作示例。
main.py 文件:
from PyQt5.QtWidgets import QWidget, QApplication, QGridLayout, QGroupBox, QPushButton, QMessageBox, QMenu
from PyQt5.QtCore import QEvent, QSettings, Qt
from PyQt5.QtGui import QIcon
class Main(QWidget):
settings = QSettings("settings.ini", QSettings.IniFormat)
def __init__(self):
super(Main, self).__init__()
self.setWindowTitle('Образец')
self.resize(500, 300)
grid = QGridLayout()
grid.addWidget(self.prog_group_box(), 0, 0, 1, 1)
grid.addWidget(self.b_new_prog(), 1, 0, Qt.AlignRight)
self.setLayout(grid)
def prog_group_box(self):
groupBox1 = QGroupBox(self)
self.grid_prog = QGridLayout()
groupBox1.setLayout(self.grid_prog)
return groupBox1
def saved_conf(self):
# Сохранение созданной кнопки в ini файл
self.settings.setValue('button', self.new_but)
self.settings.setValue('label', self.click_newprog._leProgLabel.text())
self.settings.setValue('source', self.click_newprog._leReview.text())
self.settings.sync()
# def restore_settings(self):
# Функция восстановления сохраненного конфига из ini файла
# test = self.settings.setValue('button')
# print(f'RESTORE: {test}')
def delete_setting(self):
# Функция удаления данных из ini файла с сохраненной конфигурацией
self.settings = QSettings("settings.ini", QSettings.IniFormat)
self.settings.remove('button')
def b_new_prog(self):
self.b_new_prog = QPushButton(self)
self.b_new_prog.setText("Добавить")
self.b_new_prog.setMinimumSize(129, 43)
self.b_new_prog.clicked.connect(self.click_newprog)
return self.b_new_prog
def click_newprog(self):
from second import Second
self.click_newprog = Second(self)
self.click_newprog.show()
def create_new_button(self):
self.new_but = QPushButton()
self.new_but.setFixedSize(70, 70)
self.new_but.clicked.connect(self.btnClicked)
self.new_but.setText(self.click_newprog._leProgLabel.text())
self.grid_prog.addWidget(self.new_but, 0, 0)
i = self.grid_prog.count() - 1
self.grid_prog.addWidget(self.new_but, 1 + i // 8, i % 8)
self.new_but.installEventFilter(self)
def btnClicked(self):
import os
os.startfile(self.click_newprog._leReview.text())
# Контекстное меню
def eventFilter(self, source, event):
if event.type() == QEvent.ContextMenu and source is self.new_but:
menu = QMenu()
menu.addAction('Удалить')
if menu.exec_(event.globalPos()):
reply = QMessageBox.question(
self,
'Message', "Вы действительно хотите удалить?",
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No
)
if reply == QMessageBox.Yes:
self.new_but.hide()
self.delete_setting()
else:
pass
return super().eventFilter(source, event)
if __name__ == ('__main__'):
import sys
app = QApplication(sys.argv)
w = Main()
w.show()
sys.exit(app.exec_())
第二个.py 文件:
from PyQt5.QtWidgets import (QLabel, QVBoxLayout, QLineEdit, QPushButton,
QHBoxLayout, QFileDialog, QMessageBox, QDialog)
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont
class Second(QDialog):
def __init__(self, Main):
super().__init__()
self.main = Main
self.setMinimumSize(300, 160)
self.setWindowFlags(Qt.Dialog)
vbox = QVBoxLayout()
hbox = QHBoxLayout()
hbox.addWidget(self._lProgLabel())
hbox.addWidget(self._leProgLabel())
vbox.addLayout(hbox)
vbox.addWidget(self._lReview())
hbox2 = QHBoxLayout()
hbox2.addWidget(self._leReview())
hbox2.addWidget(self._bReview())
vbox.addLayout(hbox2)
hbox3 = QHBoxLayout()
hbox3.addWidget(self.b_create())
hbox3.addWidget(self.b_close())
vbox.addLayout(hbox3)
self.setLayout(vbox)
def _lProgLabel(self):
_lProgLabel = QLabel(self)
_lProgLabel.setText('<center style=font-size:10pt><FONT FACE="Century Gothic">Название кнопки:</center>')
return _lProgLabel
def _leProgLabel(self):
self._leProgLabel = QLineEdit(self)
self._leProgLabel.setFont(QFont('Century Gothic', 10))
return self._leProgLabel
def _lReview(self):
_lreview = QLabel(self)
_lreview.setText(
'<center style=font-size:10pt><FONT FACE="Century Gothic">Укажите путь к программе или нажмите "Обзор":</center>')
return _lreview
def _leReview(self):
self._leReview = QLineEdit(self)
self._leReview.setFixedSize(250, 30)
self._leReview.setFont(QFont('Century Gothic', 10))
return self._leReview
def _bReview(self):
_breview = QPushButton()
_breview.setFixedSize(90, 30)
_breview.setText("Обзор")
_breview.clicked.connect(self.browseFiles)
return _breview
def browseFiles(self):
fname = QFileDialog.getOpenFileName(self, 'Open file', 'C:\Program Files', 'exe files (*.exe)')
self._leReview.setText(fname[0])
def b_create(self):
b_create = QPushButton(self)
b_create.setText("Добавить")
b_create.setMinimumSize(10, 40)
b_create.clicked.connect(self.create_button)
return b_create
def b_close(self):
b_close = QPushButton(self)
b_close.setText("Отмена")
b_close.setMinimumSize(10, 40)
b_close.clicked.connect(self._cancel)
return b_close
def _cancel(self):
self.close()
def showMessageBox(self, title, message):
msgBox = QMessageBox()
msgBox.setWindowTitle(title)
msgBox.setText(message)
msgBox.setStyleSheet("font: 12px;"
"font-family: Century Gothic;")
msgBox.setStandardButtons(QMessageBox.Ok)
msgBox.exec_()
# Проверка ввода данных
def create_button(self):
if len(self._leReview.text()) == 0:
self.showMessageBox('Внимание!',
'<center><br/><u style=font-size:10pt><FONT FACE="Arial"><b>Вы не заполнили поля</b></u></center></FONT>')
else:
self.main.create_new_button()
self.main.saved_conf()
self.close()
if __name__ == ('__main__'):
w = Second()
w.show()
你的问题是你每次都重新分配
self.new_but
,所以只有最后一个添加的对你有用。self.new_but
在您的任务中,在插槽中使用而不是信号源(谁调用它)就足够了-self.sender()
这里至少有一个示例:如果有人有同样的问题,这里是解决方案:
更改将仅影响文件:main.py: