Будет база данных с настройками таймеров вида:
[ { }, { }, ... { } ]
Программа работает не до конца. В левом верхем углу каждого таймера есть кнопка “Р” - редактировать настройки таймера. Если в них зайти, что-то поменять, а потом запустить таймер один раз или более, то вывваливается ошибка:
line 222, in display
self.opoveschenie()
TypeError: 'Opoveschenie' object is not callable
Да и вообще мне кажется, что код получился громоздким, буду рад услышать советы по оптимизации.
# Python 3 # -*- coding: utf-8 -*- version = '2018.01.02' # Начало разработки import sys, pickle, time, os from PyQt4 import QtCore, QtGui, Qt from PyQt4.QtGui import (QWidget, qApp, QAction, QApplication, QHBoxLayout, QVBoxLayout, QGridLayout, QLabel, QLineEdit, QTextEdit, QPushButton, QComboBox, QCheckBox, QRadioButton, QFrame, QScrollArea, QTabWidget, QSizePolicy, QGroupBox, QFileDialog, QMessageBox, QPlainTextEdit, QLCDNumber, QSpinBox, QBrush, QColor) from PyQt4.QtGui import QIcon, QPixmap, QPalette, QTextCursor from PyQt4.QtCore import QTime, QTimer from datetime import datetime PyQT = 4 # ПУТИ path_to_script = os.path.dirname(os.path.abspath(__file__)) sys.path.append(path_to_script) path_to_file_db = os.path.join(path_to_script, 'db_timery.pkl') # ГРАФИКА class Window(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) self.setMinimumSize(100, 100) # Минимальная ширина и высота окна self.resize(250, 400) # шир / выс окна #self.adjustSize() self.setWindowTitle('Таймер – '+version) # Заголовок self.setWindowIcon(QIcon('res/res_picture/icon.png')) # Иконка # ПЕРЕМЕННЫЕ self.read_db() self.box_index = 0 #self.widget_timer_lst = [] # не нужно #self.lst_obj_name = [] # индексы таймеров (виджетов) # не нужно # ПОДКЛЮЧЕНИЕ СТИЛЕЙ '''sss = open('res/dark_blue.stylesheet', 'r') self.styleData = sss.read() sss.close() self.setStyleSheet(self.styleData)''' # БЛОК РАЗМЕТКИ vbox_os = QVBoxLayout() self.vbox = QVBoxLayout() vbox_os.addLayout(self.vbox) self.button_new_timer = QPushButton('Новый таймер') self.button_new_timer.clicked.connect(self.on_new_timer) self.vbox.addWidget(self.button_new_timer) #print('self.db =',self.db) for i in range(len(self.db)): self.new_timer(i) self.widget_timer.settings_in_box() vbox_os.addStretch() self.setLayout(vbox_os) # установка рабочей области def new_timer(self, index): self.widget_timer = Timer() self.widget_timer.setStyleSheet("background-color: #517852") self.widget_timer.box_index_refinement(index) # каждый таймер знает свой индекс self.vbox.addWidget(self.widget_timer) def on_new_timer(self): self.new_timer(len(self.db)) #self.widget_timer.setObjectName('box' + str(self.box_index)) # не нужно #self.widget_timer_lst.append(self.widget_timer) # не нужно self.db_i = {} self.db.append(self.db_i) self.box_index += 1 self.save_in_file() def read_db(self): try: # если файл существует with open(path_to_file_db, 'rb') as F: # открываем файл try: self.db = pickle.load(F) # читаем содержимое в переменную except EOFError: # если файл пустой self.db = [] except FileNotFoundError: # если файл не существует F = open(path_to_file_db, 'wb') # создаём пустой файл F.close() self.db = [] # в файле нет данных def save_in_file(self): # сохранить базу в файл with open(path_to_file_db, 'wb') as f: pickle.dump(self.db, f) class Timer(QWidget): def __init__(self, *args, **kwargs): super().__init__() # Переменные self.pix_start = '►' self.pix_pause = 'II' self.pix_stop = '■' self.db = [] self.box_index = 0 self.message = 'Заданный<br>\ текст' self.at_zero = 'stop' self.time_refinement() # БЛОК РАЗМЕТКИ grid = QGridLayout(self) grid.setSpacing(2) grid.setContentsMargins(0,0,0,0) # Устанавка отступов от краёв frame = QFrame(self) frame.setFrameShape(1) frame_lay = QGridLayout(frame) grid.addWidget(frame, 0,0) # --- --- self.button_edit = QPushButton('Р') self.button_edit.setToolTip('Редактировать') self.button_edit.clicked.connect(self.on_timer_edit) frame_lay.addWidget(self.button_edit, 0,0) # --- self.lbl_name = QLabel('Название таймера') frame_lay.addWidget(self.lbl_name, 0,1,1,6) # --- self.button_del = QPushButton('X') self.button_del.setToolTip('Удалить таймер') self.button_del.clicked.connect(self.timer_del) frame_lay.addWidget(self.button_del, 0,7) # --- --- self.LCD = QLCDNumber(self) self.LCD.setDigitCount(8) self.LCD.display(str(self.hour).rjust(2, '0')+':'\ +str(self.min).rjust(2, '0')+':'\ +str(self.sec).rjust(2, '0')) # начальный текст frame_lay.addWidget(self.LCD, 1,0,1,4) # --- self.button_start = QPushButton(self.pix_start) self.button_start.setAutoDefault(True) self.button_start.clicked.connect(self.on_start) frame_lay.addWidget(self.button_start, 1,4,1,2) # --- self.button_stop = QPushButton(self.pix_stop) self.button_stop.clicked.connect(self.on_stop) frame_lay.addWidget(self.button_stop, 1,6,1,2) # --- --- self.setLayout(grid) # установка рабочей области self.timer = QTimer() self.timer.setInterval(10) self.timer.timeout.connect(self.display) def time_refinement(self, hour=None, minuty=None,sec=None): # уточнение времени self.ms = 0 self.sec = 5 if sec == None else sec self.min = 0 if minuty == None else minuty self.hour = 0 if hour == None else hour def on_start(self): self.timer.start() self.button_start.setText(self.pix_pause) self.button_start.clicked.disconnect() self.button_start.clicked.connect(self.on_pause) def on_pause(self): self.timer.stop() self.button_start.setText(self.pix_start) self.button_start.clicked.disconnect() self.button_start.clicked.connect(self.on_start) def on_stop(self): self.timer.stop() self.time_refinement() self.on_pause() self.display() def display(self): self.LCD.display("%02d:%02d:%02d" % (self.hour, self.min, self.sec)) if self.ms != 0: self.ms -= 1 else: self.ms = 99 if self.sec != 0: self.sec -= 1 else: self.sec = 59 if self.min != 0: self.min -=1 else: self.min = 59 if self.hour != 0: self.hour -= 1 else: self.opoveschenie() if self.at_zero == 'stop': # поведение при нуле self.on_stop() self.pasteText(str(self.db[self.box_index])) else: self.pasteText(str(self.db[self.box_index])) self.timer.start() def opoveschenie(self): self.opoveschenie = Opoveschenie() screen = QtGui.QDesktopWidget().screenGeometry() size = self.geometry() self.opoveschenie.move((screen.width()-size.width())/2, (screen.height()-size.height())/2) self.opoveschenie.in_text(self.message) self.opoveschenie.show() def timer_del(self): #box_index = self.box_index #print('Объект №',box_index) self.close() self.db.pop(self.box_index) self.save_in_file() def on_timer_edit(self): self.opn_settings = Settings() self.opn_settings.sendText.connect(self.pasteText) self.opn_settings.paste_setting(self.db_i) self.opn_settings.show() def pasteText(self, text): self.db_i = eval(text) self.lbl_name.setText(self.db_i.setdefault('имя таймера','Название')) self.time_refinement(int(self.db_i.setdefault('hour','0')), int(self.db_i.setdefault('min','0')), int(self.db_i.setdefault('sec','5'))) self.LCD.display(str(self.hour).rjust(2, '0')+':'\ +str(self.min).rjust(2, '0')+':'\ +str(self.sec).rjust(2, '0')) self.at_zero = self.db_i.setdefault('при нуле','stop') self.message = self.db_i.setdefault('сообщение','Текст') self.db[self.box_index].update(self.db_i) for i in range(len(self.db)): print(self.db) self.save_in_file() print('self.box_index =', self.box_index) def settings_in_box(self): self.read_db() self.db_i = self.db[self.box_index] self.lbl_name.setText(self.db_i.setdefault('имя таймера','Название')) self.time_refinement(int(self.db_i.setdefault('hour','0')), int(self.db_i.setdefault('min','0')), int(self.db_i.setdefault('sec','5'))) self.LCD.display(str(self.hour).rjust(2, '0')+':'\ +str(self.min).rjust(2, '0')+':'\ +str(self.sec).rjust(2, '0')) self.at_zero = self.db_i.setdefault('при нуле','stop') self.message = self.db_i.setdefault('сообщение','Текст') def box_index_refinement(self, i): # уточнение индекса таймера self.box_index = i #print('self.box_index =', self.box_index) def read_db(self): try: # если файл существует with open(path_to_file_db, 'rb') as F: # открываем файл try: self.db = pickle.load(F) # читаем содержимое в переменную except EOFError: # если файл пустой self.db = [] except FileNotFoundError: # если файл не существует F = open(path_to_file_db, 'wb') # создаём пустой файл F.close() self.db = [] # в файле нет данных def save_in_file(self): # сохранить базу в файл with open(path_to_file_db, 'wb') as f: pickle.dump(self.db, f) class Settings(QWidget): sendText = QtCore.pyqtSignal(str) # сигнал def __init__(self, parent=None): super().__init__(parent, QtCore.Qt.Window) self.setMinimumSize(300, 300) # Минимальная ширина и высота окна self.setMaximumSize(350, 450) # self.setWindowTitle('Настройки таймера') # Заголовок self.setWindowIcon(QIcon('res/res_picture/icon.png')) # Иконка # БЛОК РАЗМЕТКИ vbox_os = QVBoxLayout() # --- --- lbl = QLabel('<center>Название таймера:</center>') vbox_os.addWidget(lbl) # --- self.pole_name = QLineEdit(self) vbox_os.addWidget(self.pole_name) # --- --- grid_1 = QGridLayout() # установка времени vbox_os.addLayout(grid_1) # --- --- lbl = QLabel('<center>Часы:</center>') grid_1.addWidget(lbl, 0,0) # --- lbl = QLabel('<center>Минуты:</center>') grid_1.addWidget(lbl, 0,1) # --- lbl = QLabel('<center>Секунды:</center>') grid_1.addWidget(lbl, 0,2) # --- --- self.pole_hour = QSpinBox() self.pole_hour.setRange(0,99) # мин, макс знач #self.pole_hour.setSuffix(' ч') grid_1.addWidget(self.pole_hour, 1,0) # --- self.pole_min = QSpinBox() self.pole_min.setRange(0,59) # мин, макс знач self.pole_min.setSingleStep(5) # шаг grid_1.addWidget(self.pole_min, 1,1) # --- self.pole_sec = QSpinBox() self.pole_sec.setRange(0,59) # мин, макс знач self.pole_sec.setSingleStep(10) # шаг grid_1.addWidget(self.pole_sec, 1,2) # --- --- frame_radio = QFrame() # Фрейм frame_radio.setFrameShape(1) # (QtGui.QFrame.StyledPanel) frame_radio.setFrameShadow(QFrame.Raised) self.radio_group = QGroupBox("При достижении нуля", frame_radio) self.radio_lay = QVBoxLayout(self.radio_group) self.radio1 = QtGui.QRadioButton("Остановить таймер", self.radio_group) self.radio1.setChecked(True) self.radio_lay.addWidget(self.radio1) self.radio2 = QtGui.QRadioButton("Повторный запуск таймера", self.radio_group) self.radio_lay.addWidget(self.radio2) vbox_os.addWidget(self.radio_group) # --- --- lbl = QLabel('Вывести сообщение:') vbox_os.addWidget(lbl) # --- self.pole_1 = QTextEdit() vbox_os.addWidget(self.pole_1) # --- --- self.check_on_zvuk = QtGui.QCheckBox("Звук включен") self.check_on_zvuk.setCheckState(QtCore.Qt.Checked) # положение - нажат #self.check_on_zvuk.toggled.connect(self.on_start) vbox_os.addWidget(self.check_on_zvuk) # громкость (виждет) hbox = QHBoxLayout() vbox_os.addLayout(hbox) self.button_cancel = QPushButton('Отмена') self.button_cancel.clicked.connect(self.closeEvent) hbox.addWidget(self.button_cancel) self.button_ok = QPushButton('Ок') self.button_ok.clicked.connect(self.on_ok) hbox.addWidget(self.button_ok) # --- --- vbox_os.addStretch() self.setLayout(vbox_os) # установка рабочей области def on_ok(self, event): self.db_i = {} self.db_i['имя таймера'] = self.pole_name.text() self.db_i['hour'] = str(self.pole_hour.value()).rjust(2, '0') self.db_i['min'] = str(self.pole_min.value()).rjust(2, '0') self.db_i['sec'] = str(self.pole_sec.value()).rjust(2, '0') radio1 = self.radio1.isChecked() if radio1 == 1: self.db_i['при нуле'] = 'stop' else: self.db_i['при нуле'] = 'restart' self.db_i['сообщение'] = self.pole_1.toPlainText() self.db_i['звук включен'] = str(self.check_on_zvuk.isChecked()) # 1 - нажат self.db_i['громкость'] = 0 self.close() self.sendText.emit(str(self.db_i)) # посылаем сигнал по клику def paste_setting(self, db_i): self.pole_name.setText(db_i.setdefault('имя таймера','Название')) self.pole_hour.setValue(int(db_i.setdefault('hour',0))) self.pole_min.setValue(int(db_i.setdefault('min',0))) self.pole_sec.setValue(int(db_i.setdefault('sec',0))) if db_i.setdefault('при нуле','stop') == 'stop': self.radio1.setChecked(True) else: self.radio2.setChecked(True) self.pole_1.setText(db_i.setdefault('сообщение','Текст')) if db_i.setdefault('звук включен','') == 'True': # звук включен self.check_on_zvuk.setCheckState(QtCore.Qt.Checked) # установлен QtCore.Qt.Checked else: self.check_on_zvuk.setCheckState(0) # сброшен def closeEvent(self, event): self.close() class Opoveschenie(QWidget): def __init__(self, *args, **kwargs): super().__init__() # parent, QtCore.Qt.Window self.setMinimumSize(100, 100) # Минимальная ширина и высота окна self.adjustSize() self.setWindowTitle('Оповещение') # Заголовок self.setWindowIcon(QIcon('res/res_picture/icon.png')) # Иконка # окно на передний план: self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint) sss_vivod = ("color: #f2f2f0; font: 16pt 'Courier New'") # БЛОК РАЗМЕТКИ vbox_os = QVBoxLayout() # --- self.pole_1 = QTextEdit() self.pole_1.setReadOnly(1) self.pole_1.setStyleSheet(sss_vivod) vbox_os.addWidget(self.pole_1) # --- --- self.button_ok = QPushButton('Ок') self.button_ok.clicked.connect(self.closeEvent) vbox_os.addWidget(self.button_ok) # --- --- vbox_os.addStretch() self.setLayout(vbox_os) # установка рабочей области def in_text(self, text): self.pole_1.setText('<center>'+text+'</center>') def closeEvent(self, event): self.close() # КОНЕЦ if __name__ == "__main__": app = QApplication(sys.argv) window = Window() window.move(40,20) window.show() sys.exit(app.exec_())