Уведомления

Группа в Telegram: @pythonsu

#1 Янв. 21, 2018 21:15:56

Kyrym
Зарегистрирован: 2016-12-28
Сообщения: 225
Репутация: +  3  -
Профиль   Отправить e-mail  

PyQT4 | Мультитаймер.

Делаю программу мультитаймер. Есть окно (вертикальный бокс), в которое добавляется n-ое количество таймеров (см. код), реализованных как виджеты.
Будет база данных с настройками таймеров вида:

 [ { },
  { },
  ...
  { } ]
Здесь каждая строка - это словарь с настройками одного таймера.
Программа работает не до конца. В левом верхем углу каждого таймера есть кнопка “Р” - редактировать настройки таймера. Если в них зайти, что-то поменять, а потом запустить таймер один раз или более, то вывваливается ошибка:
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_())

Отредактировано Kyrym (Янв. 21, 2018 21:21:47)

Офлайн

#2 Янв. 22, 2018 15:51:23

PEHDOM
Зарегистрирован: 2016-11-28
Сообщения: 2196
Репутация: +  294  -
Профиль   Отправить e-mail  

PyQT4 | Мультитаймер.

Я вообще не могу зайти в настройки вываливается AttributeError: ‘Timer’ object has no attribute ‘db_i’
но ладно, методом научного тыка избавились от ошибки.
замечания:
1. зачем эта дикость self.sendText.emit(str(self.db_i))? что вам мешает передавать словарь в сигнале? тогда вам не нужен будет следующий пункт.
2. Следующее self.db_i = eval(text), опять же дичь, на крайний случай есть же ast.literal_eval.
3. для Settings имхо лучше использовать не QWidget, а QDialog, тогда не нужно будет этот геморой с сигналом и пункты 1 и 2. Его(QDialog) как раз и придумали для подобных случаев.

Kyrym
вывваливается ошибка:

TypeError: ‘Opoveschenie’ object is not callable
ну да а что вы хотели?
     def opoveschenie(self):
        self.opoveschenie = Opoveschenie()
вы же в самом методе после первого вызова, заменяете метод, на экземпляр класса Opoveschenie. естественно он не каллабельный, поскольку у него нету метода __call__(), о чем вам честно сообщает интерпретатор.
Kyrym
буду рад услышать советы по оптимизации.
ХЗ конечно, но хранить в каждом виджете его индекс, это не лучший вариант. При условии что у вас динамическая структура, вам придется каждый раз при удалении непоследнего виджета перестраивать индексы у всех таймеров. Не что чтобы это особенно сложно, но это лишний код.
Имхо гораздо проще помещать их в список, а допустим при удалении гененрировать сигнал, в котором будет передаваться ссылка на сам виджет.
У вас в каждом таймере вы считываете полностью “базу” с записями о всех таймерах, и выбираете свой, что тоже не есть гуд. При изменении настроек оно опять лезет в “базу” и само ее правит что вообще моветон. Таймер вообще не должен знать что гдето чтото храниться, это должна знать основная программа, и передавать в таймер/брать из него только нужную ему информацию.
я чутка поправил ваш код чтоб было хоть какоето бщее понимание, надеюсь разберетесь.
 # 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.read_db()
        self.widget_timer_lst = [] # нужно
        # ПОДКЛЮЧЕНИЕ СТИЛЕЙ
        '''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()
        vbox_os.addStretch()
        self.setLayout(vbox_os) # установка рабочей области
    def timer_delete(self, timer):
        # PEHDOM change
        index = self.widget_timer_lst.index(timer)
        timer.timer_deleted.disconnect()
        timer.setting_changed.disconnect()
        print('deleting timer with index: {}'.format(index))
        self.widget_timer_lst.pop(index)
        self.db.pop(index)
        self.save_in_file()
        self.vbox.removeWidget(timer)
        timer.deleteLater()
    def timer_change_settings(self, timer):
        # PEHDOM change
        index = self.widget_timer_lst.index(timer)
        print('timer {} change settings, new settigs:{}'.format(index, timer.db_i))
        print('обновление "базы" напишете сами..')
    def new_timer(self):
        # PEHDOM change
        widget_timer = Timer()
        self.widget_timer_lst.append(widget_timer)
        widget_timer.timer_deleted.connect(self.timer_delete)
        widget_timer.setting_changed.connect(self.timer_change_settings)
        widget_timer.setStyleSheet("background-color: #517852")
        self.vbox.addWidget(widget_timer)
        widget_settings = self.db[len(self.widget_timer_lst)-1]
        widget_timer.pasteText(str(widget_settings))
    def on_new_timer(self):
        self.db_i = {}
        self.db.append(self.db_i)
        self.new_timer()
        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 IOError: # если файл не существует
            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):
    timer_deleted = QtCore.pyqtSignal(object)  # сигнал что таймер нужно удалить
    setting_changed = QtCore.pyqtSignal(object) # сигнал что у таймера поменялись настройки
    def __init__(self, *args, **kwargs):
        super().__init__()
        # Переменные
        self.pix_start = '►'
        self.pix_pause = 'II'
        self.pix_stop = '■'
        self.db_i = []
        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_i)) # ХЗ зачем?
                        else:
                            #self.pasteText(str(self.db_i)) # ХЗ зачем?
                            self.timer.start()
    def opoveschenie(self):
        # PEHDOM cnahge
        self.op_window = Opoveschenie()
        screen = QtGui.QDesktopWidget().screenGeometry()
        size = self.geometry()
        self.op_window.move((screen.width()-size.width())/2, (screen.height()-size.height())/2)
        self.op_window.in_text(self.db_i['сообщение'])
        self.op_window.show()
    def timer_del(self):
        # PEHDOM change
        self.close()
        self.timer_deleted.emit(self)
    def settings_changed(self, text):
         # PEHDOM change
        self.pasteText(text)
        self.setting_changed.emit(self)
    def on_timer_edit(self):
        # PEHDOM пока оставил как есть, но лучше использовать QDialog.
        self.opn_settings = Settings()
        self.opn_settings.sendText.connect(self.settings_changed)
        self.opn_settings.paste_setting(self.db_i)
        self.opn_settings.show()
    def pasteText(self, text):
        # PEHDOM пока оставил как есть, но лучше передавать словарь сразу
        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('сообщение','Текст')
class Settings(QWidget):
    # PEHDOM пока оставил как есть, но лучше использовать QDialog, и в сигнале передавать словарь или список аргументов (по желанию)
    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) # сброшен
    #  # PEHDOM deleted, reason: не нужно
    #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()
    def __call__(self):
        print('calling_method')
# КОНЕЦ
if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = Window()
    window.move(40,20)
    window.show()
    sys.exit(app.exec_())



==============================
Помещайте код в теги:
[code python][/code]
Бериегите свое и чужое время.

Отредактировано PEHDOM (Янв. 22, 2018 16:00:14)

Офлайн

#3 Янв. 23, 2018 20:59:42

Kyrym
Зарегистрирован: 2016-12-28
Сообщения: 225
Репутация: +  3  -
Профиль   Отправить e-mail  

PyQT4 | Мультитаймер.

1. Получается, что класс Opoveschenie() нет смысла переводить на QDialog, поскольку не имеет преимуществ перед QWidget, когда нужно передать данные в дочернее окно.
2. Чтения документации по QDialog мне не достаточно, чтобы разобраться, как диалоговое окно передаст словарь родителю.
На сколько я понял, есть слоты accept (), done ( int r ) первый возвращает Accepted = 1, а второй какое-то r (не знаю, что это такое)
Есть сигналы accepted () и finished ( int result )
void QDialog::finished ( int result )
Данный сигнал испускается при установке кода результата диалога (result) пользователем…
Хм.. Чтобы это значило?
У меня есть словарь self.db_i - это результат, мне нужно его передать основной программе. Но словарь не является int, поэтому для сигнала это не тот результат.

      def opoveschenie(self):
        self.opoveschenie = ...
О переопределении я не подумал.
PEHDOM
У вас в каждом таймере вы считываете полностью “базу” с записями о всех таймерах, и выбираете свой, что тоже не есть гуд. При изменении настроек оно опять лезет в “базу” и само ее правит что вообще моветон. Таймер вообще не должен знать что гдето чтото храниться, это должна знать основная программа, и передавать в таймер/брать из него только нужную ему информацию.
Согласен со всем.
PEHDOM
 #self.pasteText(str(self.db_i)) # ХЗ зачем?
После срабатывания таймера self.min и остальные уходят в ноль, поэтому нужно восстановить время по базе данных, в противном случае устанавливается 5 секунд.


Отредактировано Kyrym (Янв. 23, 2018 21:51:20)

Офлайн

#4 Янв. 24, 2018 13:13:40

KriO
Зарегистрирован: 2012-10-07
Сообщения: 61
Репутация: +  9  -
Профиль   Отправить e-mail  

PyQT4 | Мультитаймер.

Использовать для оповещения QDialog гораздо удобнее, чем QWidget, т.к. в родительском классе после определения этого диалога вы можете определить сигнал, по которому будете брать нужный вам словарь из диалога:
self.opoveschenie.accepted.connect(self.getDict)
В методе getDict() вызовете метод self.opoveschenie.getDict(), который вернёт нужный словарь.
В классе Opoveschenie вы можете переопределить методы accept() и reject() и делать в них то, что нужно в случае хорошего и плохого завершения соответственно.
Для выдачи сообщений есть, кстати, готовый диалог QWarningDialog.

Офлайн

#5 Янв. 24, 2018 16:20:08

PEHDOM
Зарегистрирован: 2016-11-28
Сообщения: 2196
Репутация: +  294  -
Профиль   Отправить e-mail  

PyQT4 | Мультитаймер.

Kyrym
2. Чтения документации по QDialog мне не достаточно, чтобы разобраться, как диалоговое окно передаст словарь родителю.
да там все просто и банально:
 class Settings(QDialog):
    def __init__(self, parent=None):
       ....
        btnBox=QtGui.QDialogButtonBox(self) # Добавляем секцию с кнопками ОК,Cancel и тд..
        vbox_os.addWidget(btnBox)           # Помещаем на форму...
        btnBox.setStandardButtons(QtGui.QDialogButtonBox.Ok| QtGui.QDialogButtonBox.Cancel)  # Добавляем кнопки ОК и Cancel
        btnBox.accepted.connect(self.accept)  # соединяем действия кнопок с формой,
        btnBox.rejected.connect(self.reject)  #
        ....
def on_ok(self):
        self.db_i = {}
        ....
        self.db_i['громкость'] = 0
        return self.db_i
тогда вызов окна выглядит так
     def on_timer_edit(self):
        opn_settings = Settings() # создаем екземпляр Settings
        opn_settings.paste_setting(self.db_i) # предаем в окно текущие настройки
        if opn_settings.exec() == opn_settings.Accepted: # Откываем окно и "ждем" его закрытия, Если нажали ОК
            new_setts = opn_settings.on_ok()  # получаем в new_setts новые настройки из окна
            print(new_setts) # дальше делаем что хотим из новых натроек
        else: # Если нажали Кенсл
            pass # тоже можно чтото прописать

Kyrym
1. Получается, что класс Opoveschenie() нет смысла переводить на QDialog, поскольку не имеет преимуществ перед QWidget, когда нужно передать данные в дочернее окно.
ХЗ, если вам не нужно “чегото эдакого” посмотрите в сторону уже готового QMessageBox


ЗЫ Если окно настроек имеет непосредственное отношение к таймеру, и больше нигде не имеет смысла, то окно Opoveschenie я бы вынес из класса таймера.
Таймер по завершении работы должен испускать сигнал “finished” или “sucsess” или еще как нить, а уже главная программа реагировать на сигнал и выводить окно сообщения. ИМХО.



==============================
Помещайте код в теги:
[code python][/code]
Бериегите свое и чужое время.

Отредактировано PEHDOM (Янв. 24, 2018 17:04:57)

Офлайн

#6 Янв. 24, 2018 17:15:51

Kyrym
Зарегистрирован: 2016-12-28
Сообщения: 225
Репутация: +  3  -
Профиль   Отправить e-mail  

PyQT4 | Мультитаймер.

 btnBox.accepted.connect(self.accept)  # соединяем действия кнопок с формой,
btnBox.rejected.connect(self.reject)  #
А так можно сделать с обычными кнопками или только через QDialogButtonBox?
(Проверил, не получилось)

Вопрос. Если я пишу так:
 class Settings(QDialog):
    sendText = QtCore.pyqtSignal(dict) # сигнал
...
class Timer(QWidget):
...
    def pasteText(self, db_i): # вставляет настройки в виджет таймера из базы
        self.db_i = db_i
Т.е. пытаюсь из настроек передать не строку (как было), а словарь, то shell пишет, что self.db_i, получаемое в pasteText(), всё равно является строкой. Т.е. словарь так передать нельзя?

KriO
QWarningDialog
В PyQT4 я не нашёл такого класса, это, наверно, PyQT5? В нём родитель передаёт в дочернее окно текст?
По смыслу Ваш пост не про класс Opoveschenie, а про класс Settings.
Класс Opoveschenie - это всплывающее окно, которое выводит некий текст из родителя и всё.
Класс Settings - это дочернее окно с настройками, которое берёт словарь из базы данных и возвращает словарь по “положительному” закрытию.
——————————————————
На текущий момент в целом программа работает, правда, звук не реализован.
PEHDOM,я посмотрел Ваш пример с QDialog, и думаю, что ради экономии нескольких строк нет смысла переделывать сигналы. Вообще, ну передам я словарь из Settings в Timer через accepted, но мне же потом нужно будет передавать этот словарь из Timer в основной класс (теперь Control), т.е. тут всё равно создавать свои сигналы.
_________________________________
У меня есть ещё 2 вопроса:
1. Если создавать таймеры, то окно программы будет увеличиваться:
 self.win_height += 80
self.resize(self.win_width, self.win_height) # шир / выс окна
Однако, при первом удалении таймера, окно не изменяется, только при последующих. Почему так?
2. Ищу простой способ воспроизведения звуков. Можно wav. Вот только простого способа нету, надо обязательно какие-то модули ставить, стандартных способов нет? Phonon, к примеру, вообще устанавливать надо?
А есть модуль, чтобы просто в папку положить и подключить его как обычный модуль, без установки в систему? И чтобы работало на линуксе и винде.

 # Python 3
# -*- coding: utf-8 -*-
# '2018.01.02-21' # Начало разработки
# '2018.01.23' # Окно оповещения и настроек через QDialog,
# разные правки
version = '2018.01.24' # вариант работает, добавлен ползунок
# добавлен индикатор звука 
import sys, pickle, time, os, ast #, Phonon.phonon
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, QDialog,
                         QBrush, QColor)
from PyQt4.QtGui import QIcon, QPixmap, QPalette, QTextCursor
from PyQt4.QtCore import QTime, QTimer
from datetime import datetime
# ПУТИ
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')
path_to_file_audio = os.path.join(path_to_script, 'Message.wav')
# ГРАФИКА
class Control(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        # ПЕРЕМЕННЫЕ
        self.read_db()
        self.widget_timer_lst = []
        self.win_width = 250
        self.win_height = 50
        
        # ПАРАМЕТРЫ ОКНА
        self.setMinimumSize(250, 50) # Минимальная ширина и высота окна
        self.resize(self.win_width, self.win_height) # шир / выс окна
        self.setWindowTitle('Таймер – '+version) # Заголовок
        path_to_file_icon = os.path.join(path_to_script, 'res/res_picture/icon.png')
        self.setWindowIcon(QIcon(path_to_file_icon)) # Иконка
        # ПОДКЛЮЧЕНИЕ СТИЛЕЙ
        '''path_to_file_sss = os.path.join(path_to_script, 'res/dark_blue.stylesheet')
        sss = open(path_to_file_sss, '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)
        for i in range(len(self.db)):
            self.new_timer()
             
        vbox_os.addStretch()
        
        self.setLayout(vbox_os) # установка рабочей области
        
    def timer_delete(self, timer):
        index = self.widget_timer_lst.index(timer)
        timer.timer_deleted.disconnect()
        timer.setting_changed.disconnect()
        #print('deleting timer with index: {}'.format(index))
        self.widget_timer_lst.pop(index)
        self.db.pop(index)
        self.save_in_file()
        self.vbox.removeWidget(timer)
        timer.deleteLater()
        self.win_height -= 80
        self.resize(self.win_width, self.win_height) # шир / выс окна
    def timer_change_settings(self, cor):
        timer = cor[0]
        db_i = cor[1]
        index = self.widget_timer_lst.index(timer)
        #print('timer {} change settings, new settigs:{}'.format(index, timer.db_i))
        db_i = ast.literal_eval(db_i) # из строки делает словарь
        self.db[index].update(db_i)
        self.save_in_file()
        
    def new_timer(self):
        widget_timer = Timer()
        self.widget_timer_lst.append(widget_timer)
        widget_timer.timer_deleted.connect(self.timer_delete)
        widget_timer.setting_changed.connect(self.timer_change_settings)
        widget_timer.setStyleSheet("background-color: #517852")
        self.vbox.addWidget(widget_timer)
        widget_settings = self.db[len(self.widget_timer_lst)-1]
        widget_timer.db_in_box(str(widget_settings))
        self.win_height += 80
        self.resize(self.win_width, self.win_height) # шир / выс окна
        
    def on_new_timer(self):
        self.db_i = {}        
        self.db.append(self.db_i)
        self.new_timer()
        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):
    timer_deleted = QtCore.pyqtSignal(object)
    setting_changed = QtCore.pyqtSignal(object)
    def __init__(self, *args, **kwargs):
        super().__init__()
        # ПЕРЕМЕННЫЕ
        self.pix_start = '►'
        self.pix_pause = 'II'
        self.pix_stop = '■'
        self.pix_zvuk_on = 'Зв'
        self.pix_zvuk_off = '<s>Зв</s>'
        self.db = []
        self.box_index = 0
        self.message = 'Заданный<br>\
                        текст'
        self.at_zero = 'stop'
        self.zvuk = 'True'
        self.slider_val = 90
        self.ms = 0
        self.sec = 5
        self.min = 0
        self.hour = 0
        
        # БЛОК РАЗМЕТКИ
        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,5)
        # ---
        self.lbl_zvuk = QLabel(self.pix_zvuk_on)
        frame_lay.addWidget(self.lbl_zvuk, 0,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): # уточнение времени
        self.ms = 0
        self.sec = int(self.db_i.setdefault('sec','5'))
        self.min = int(self.db_i.setdefault('min','0'))
        self.hour = int(self.db_i.setdefault('hour','0'))
    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)
        self.display()
    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()
                        else:
                            self.on_stop()
                            self.time_refinement()
                            self.on_start()
                        
    def opoveschenie(self):
        self.op_window = Opoveschenie()
        screen = QtGui.QDesktopWidget().screenGeometry()
        size = self.geometry()
        self.op_window.move((screen.width()-size.width())/2, (screen.height()-size.height())/2)
        self.op_window.in_text(self.message)
        self.op_window.exec()
    def timer_del(self):
        self.close()
        self.timer_deleted.emit(self)
        
    def settings_changed(self, db_i):
        self.db_in_box(db_i)
        self.setting_changed.emit((self, db_i)) # передаётся кортеж
    def on_timer_edit(self):
        self.opn_settings = Settings()
        # при изм настроек:
        self.opn_settings.sendText.connect(self.settings_changed)
        # отправить словарь из БД в настройки:
        self.opn_settings.paste_setting(self.db_i)
        self.opn_settings.show()
    def db_in_box(self, db_i): # вставляет настройки из базы в виджет таймера
        self.db_i = ast.literal_eval(db_i) # из строки делает словарь
        self.time_refinement()        
        self.paste_text(self.db_i)
    def settings_in_box(self): # вставляет настройки из Settings в виджет таймера
        self.db_i = self.db[self.box_index]        
        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.paste_text(self.db_i)
    def paste_text(self, db_i): # заполнение виджета таймера
        self.lbl_name.setText(self.db_i.setdefault('имя таймера','Название'))
        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.zvuk = self.db_i.setdefault('звук включен','True')
        self.slider_val = int(self.db_i.setdefault('громкость','90'))
        if self.zvuk == 'True':
            self.lbl_zvuk.setText(self.pix_zvuk_on)
        else:
            self.lbl_zvuk.setText(self.pix_zvuk_off)
       
class Settings(QDialog):
    sendText = QtCore.pyqtSignal(str) # сигнал
    def __init__(self, parent=None):
        QDialog.__init__(self)
        
        self.setMinimumSize(300, 300) # Минимальная ширина и высота окна
        self.setMaximumSize(350, 450) #
        self.setWindowTitle('Настройки таймера') # Заголовок
        path_to_file_icon = os.path.join(path_to_script, 'res/res_picture/icon.png')
        self.setWindowIcon(QIcon(path_to_file_icon)) # Иконка
        # БЛОК РАЗМЕТКИ
        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) # положение - нажат
        vbox_os.addWidget(self.check_on_zvuk)
        # --- ---
        lbl = QLabel('Громкость звука:')
        vbox_os.addWidget(lbl)
        # ---
        # ползунок громкости
        self.slider = QtGui.QSlider(QtCore.Qt.Horizontal) # горизонтальный ползунок
        self.slider.setRange(0, 100)
        self.slider.setValue(90)
        vbox_os.addWidget(self.slider)
        #self.slider_2 = VolumeSlider()
        #vbox_os.addWidget(self.slider_2)
        # --- ---
        hbox = QHBoxLayout()
        vbox_os.addLayout(hbox)
        self.button_cancel = QPushButton('Отмена')
        self.button_cancel.clicked.connect(self.reject) # закрывает окно без возврата
        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['громкость'] = str(self.slider.value())
        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) # сброшен
        
class Opoveschenie(QDialog):
    def __init__(self, *args, **kwargs):
        QDialog.__init__(self, parent=None)
        
        self.setMinimumSize(100, 100) # Минимальная ширина и высота окна
        self.adjustSize()
        self.setWindowTitle('Оповещение') # Заголовок
        path_to_file_icon = os.path.join(path_to_script, 'res/res_picture/icon.png')
        self.setWindowIcon(QIcon(path_to_file_icon)) # Иконка
        # окно на передний план:
        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 = Control()    
    window.move(40,20)
    window.show()
    sys.exit(app.exec_())

Отредактировано Kyrym (Янв. 24, 2018 21:47:56)

Офлайн

#7 Янв. 25, 2018 16:07:39

PEHDOM
Зарегистрирован: 2016-11-28
Сообщения: 2196
Репутация: +  294  -
Профиль   Отправить e-mail  

PyQT4 | Мультитаймер.

Kyrym
Т.е. пытаюсь из настроек передать не строку (как было), а словарь, то shell пишет, что self.db_i, получаемое в pasteText(), всё равно является строкой. Т.е. словарь так передать нельзя?
все передается, просто у пайтона динамическая типизация,проверте гдето в коде остался перевод к строке. вот оно вам строку и передает.
Kyrym
Однако, при первом удалении таймера, окно не изменяется, только при последующих. Почему так?
даже не представляю, Я запустил ваш пример, при удалении окно сразу изменяет размер.
Kyrym
2. Ищу простой способ воспроизведения звуков. Можно wav. Вот только простого способа нету, надо обязательно какие-то модули ставить, стандартных способов нет? Phonon, к примеру, вообще устанавливать надо?
https://pypi.python.org/pypi/playsound/1.2.1
проще некуда, всего одна функция и два аргумента, второй аргумент необязателен. кроссплатформенный, не требует зависимостей. Тоесть по идее можно просто положить модуль в папку с основным скриптом.



==============================
Помещайте код в теги:
[code python][/code]
Бериегите свое и чужое время.

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version