Ответы пользователя по тегу Python
  • PyQt5 вывод результата функции в окно виджета?

    @Sergey6661313
    1) для кода есть специальная кнопочка при оформлении вопроса (3 точки и выбрать code)
    2) написали бы хотябы как именно пытались установить в форму текст. Ну например хотябы так:
    def buttonClicked(self):
            print((a[9:]))
            window.tree.setText(str(a[9:]))
            sender = self.sender()

    А потом уже код ошибки или на что он у вас там ругается...
    Ответ написан
    3 комментария
  • PyQt Как проставить connect для неизвестного количества кнопок на форме?

    @Sergey6661313
    Наверное больше никогда не буду пользоваться лямбдами. Не ожидал такого подвоха от них.

    # coding=utf-8
    
    import sys
    from PyQt4 import QtGui
    from PyQt4.QtGui import QPushButton, QTableWidget
    from PyQt4.Qt import QApplication
    window = QApplication(sys.argv)
    
    class myTable(QTableWidget):
        class MyCustomEditButton(QPushButton):
            def __init__(self, i, name):
                self.i = i
                super().__init__(name)
                self.clicked.connect(self.slot_pressed)
    
            def slot_pressed(self):
                window.tableWidget.StartStop(self.i)
    
    
        def __init__(self):
            super().__init__()
            self.data = [
                ["1 строка"],
                ["2 строка"],
                ["3 строка"],
                ["4 строка"],
                ["5 строка"]
            ]
            self.datacount = len(self.data)
            self.setColumnCount(len(self.data[0])+1)
            self.setRowCount(self.datacount)
    
            for i in range(self.datacount):
                btn = self.MyCustomEditButton(i, "Edit")
    
                self.data0 = str(self.data[i][0])
                self.setItem(i, 0, QtGui.QTableWidgetItem(self.data0))
                self.setCellWidget(i, 1, btn)
    
        def StartStop(self, bb):
            print(bb)
    
    
    window.tableWidget = myTable()
    window.tableWidget.show()
    window.exec()


    Пробуйте, разбирайте. Вообще странное поведение питона. Как то не инстинктивно.
    Ответ написан
    Комментировать
  • Почему при вызове setHtml программа вылетает?

    @Sergey6661313
    res = requests.get('http://URL/'+trek+".html")
    orly?
    ну ей богу написали хотя бы "yandex.ru/index.html" для примера.

    без объяснения причин
    ну пожалуйста пользуйтесь pycharm - есть бесплатная редакция. Он честно открывает консоль для каждой запущенной программы. В которую честно пишется причина. И которая, Самое главное, не закрывается после ошибки.

    куски кода надо делать минимальными, НО запускаемыми. например такими:
    import sys
    import requests
    import os
    from PyQt5.QtWidgets import QTextBrowser
    from PyQt5.Qt import QApplication
    from PyQt5.Qt import QThread
    
    trek = "index"
    myapp = QApplication(sys.argv)
    myapp.textBrowser = QTextBrowser()
    
    class ExperementalThread(QThread):
        def run(self):
            if os.path.exists("temp/"+trek+".html"):  # Если страница уже была ранее загружена
                with open("temp/"+trek+".html") as w:
                    myapp.textBrowser.setHtml(w.read())  # ни разу не вылетело
            else:
                res = requests.get('http://yandex.ru/'+trek+".html")
                res.encoding = 'utf-8'
                with open("temp/"+trek+".html", "w") as ri:
                    ri.write(res.text)
                myapp.textBrowser.setHtml(res.text)  # И здесь
    
    thread = ExperementalThread()
    myapp.textBrowser.show()
    thread.start()
    myapp.exec()


    и ошибка соотв. будет QObject: Cannot create children for a parent that is in a different thread.
    что значит что метод setHtml пытается для себя создать отдельный поток. А потоки из потоков создавать запретил сам батюшка Ленин ( цитата от ██.██.19██г. ).

    Значит придётся использовать сигналы и слоты.
    я создал свой класс MyQTextBrowser с наследованием QTextBrowser и сигналом signal_load_html. Который в свою очередь связал с setHTML.

    # coding=utf-8
    
    import sys, requests, os                            # импортировали,
    from PyQt5.Qt        import QApplication, QThread   # импортировали,
    from PyQt5.QtCore    import pyqtSignal              # да не
    from PyQt5.QtWidgets import QTextBrowser            # выпереимпортировали.
    
    trek = "index"                                      # ну в самом деле надо же указать чему равна ваша переменная.
    myapp = QApplication(sys.argv)                      # я угадал?
                                                        # обязательно делаем отступы перед каждым классом
    class MyQTextBrowser(QTextBrowser):                 # создаём класс и наследуем QTextBrowser
        signal_load_html = pyqtSignal(str)              # назначаем сигнал (сигнал принимает значение str (строки) )
                                                        # тут тоже отступ
        def __init__(self):                             # переназначаем метод создания объектов
            super().__init__()                          # наследуем/выполняем QTextBrowser.__init__(self)
            self.signal_load_html.connect(self.setHtml) # тут связываем наш сигнал с setHtml
    myapp.textBrowser = MyQTextBrowser()                # ну и создаём вообщемто обьект нашего класса MyQTextBrowser
                                                        # обязательно делаем отступы после каджого класса.
                                                        # обязательно делаем отступы перед каждым классом
    class ExperementalThread(QThread):                  # названия придумываем на ходу
        def run(self):                                  # init не нужен сразу run
            if os.path.exists("temp/"+trek+".html"):    # Если страница уже была ранее загружена
                with open("temp/"+trek+".html") as w:   # открываем наш фаил в папке temp
                    # myapp.textBrowser.setHtml(w.read())  # вылетает? у меня кстати нет, но я читер :)
                    myapp.textBrowser.signal_load_html.emit(w.read())  # ни разу не вылетело.
            else:                                       # люблю когда много коментариев в коде
                res = requests.get('http://yandex.ru/'+trek+".html") # "Люблю говорить - это помогает думать."
                res.encoding = 'utf-8'                  # -- Томас Стернз Элиот
                with open("temp/"+trek+".html", "w") as ri: # когда этот код уже кончится?
                    ri.write(res.text)                  # тут пусто потому что в оригинале у вас был "URL" а не yandex
                # myapp.textBrowser.setHtml(res.text)   # И здесь
                myapp.textBrowser.signal_load_html.emit(res.text)  # ни разу не вылетело
                                                        # обязательно делаем отступы после каждого класса.
    thread = ExperementalThread()                       # создаём наш поток
    myapp.textBrowser.show()                            # ах да - самое главное показать окно. Иначе ничего не произойдёт
    thread.start()                                      # запускаем поток
    myapp.exec()                                        # Ой, всё!()


    p.s.
    Вообще setHtml не метод QTextBrowser. Это метод из QTextEdit (который QTextBrowser наслеует. ) Сам же QTextBrowser создан для того чтобы самостоятельно загружать и показывать страницы с интернета. (по урлу.)
    Ответ написан
    1 комментарий
  • Питон добавление в ComboBox?

    @Sergey6661313
    бла-бла-бла создавать comboBox как переменную создаваемого объекта OpenFile:
    class OpenFile(QtGui.QMainWindow):
        def __init__(self, parent=None):
          ...   ...   ...
          self.comboBox = QtGui.QComboBox(self)
          self.comboBox.setGeometry(QtCore.QRect(25, 55, 125, 25))
          self.comboBox.setObjectName(self.trUtf8("comboBox"))

    тогда в методе showDialog можно обратится к self.comboBox:

    for sName in wbr.sheet_names():
            sheetName.append(wbr.sheet_by_name(sName))
            self.comboBox.addItem(str(sName))


    бла-бла-бла узнать его индекс можно методом currentIndex()
    sheet = wbr.sheet_by_index(self.comboBox.currentIndex())


    бла-бла-бал отдельным методом бла-бла-бла.
    ____________________________________________________________________________________________
    дополнение к ответу:
    подытожим: мы уже заменили все comboBox на self.comboBox (вы ведь так сделали ?)
    убрали к (недружелюбное слово) sheetName и цикл его заполнения. (зачем он вам если у вас есть отличный comboBox?)
    так же сам wbr нам тоже придётся сделать "долгоиграющей" переменной (мы его будем использовать в нашем "отдельном" методе, поэтому потерять его будет катастрофой. )

    т.е довели метод def showDialog(self):
    до след. 3-х строчек:
    filename = QtGui.QFileDialog.getOpenFileName(self, 'Выбор файла', '*xls')
    self.wbr = xlrd.open_workbook(filename, formatting_info=True)
    self.comboBox.addItems(self.wbr.sheet_names())

    Что же делать со всем этим кодом ниже?
    ну можно сделать ещё одну кнопочку "писать_в_csv" и метод-слот для вашего кода.
    пример для связи кнопки и метода уже есть в вашем примере. нужно просто перед вашим кодом написать def вставте_суда_любое_название(self): и кнопку продублировать просто указать другое имя и другие координаты и там где connect поменять всё соответственно. И просто нажимать на кнопку после того как выберете лист.
    class OpenFile(QtGui.QMainWindow):
        def __init__(self, parent=None):
            QtGui.QMainWindow.__init__(self, parent)
            ...  ...  ...
    
            pButton2 = QtGui.QPushButton('записать в csv', self)
            pButton2.setGeometry(175, 55, 125, 25)
            self.connect(pButton2, QtCore.SIGNAL('clicked()'), self.slot_list_selected)
    
        def showDialog(self):
            filename = QtGui.QFileDialog.getOpenFileName(self, 'Выбор файла', '*xls')
            self.wbr = xlrd.open_workbook(filename, formatting_info=True)
            self.comboBox.addItems(self.wbr.sheet_names())
    
        def slot_list_selected(self):
            # //////////////////Индекс листа///////////////////////
            sheet = self.wbr.sheet_by_index(self.comboBox.currentIndex())
    
            ... ... ...


    Но мы же не ищем легких путей ведь так?
    + мы хотим познакомится с QT поближе.
    наш тру вариант без участия дополнительной кнопки:
    метод я назвал slot_list_selected. и мы его соединим непосредственно с сигналом изменения combobox-а так:
    self.comboBox.currentIndexChanged.connect(self.slot_list_selected) - это альтернативный более коротки метод связывания сигналов и слотов (чем self.connect(self.comboBox, QtCore.SIGNAL('currentIndexChanged(int)'), self.slot_list_selected) )
    но есть запарка - сигнал не только вызывает метод но и передает ему int (выбранный индекс). Значит наш слот-метод должен его принимать.
    def slot_list_selected(self, list_index):
    ну и так как он нам всё равно передается мы могли бы его сразу использовать.
    заместо sheet = self.wbr.sheet_by_index(self.comboBox.currentIndex())
    sheet = self.wbr.sheet_by_index(list_index)
    в принципе дальше ваш магический код вроде прекрасно работает. но он будет вызыватся в момент когда мы заполняем наш comboBox (изначально пустой combo показывает "-1", а когда заполняем его значение становится "0" что вызывает сигнал currentIndexChanged)
    это решается выключением сигналов коммандой self.comboBox.blockSignals(True)
    Но и тут вылезут подводные камни: в частности по умолчанию выберется первый элемент(с индексом 0) и попытавшись его выбрать индекс не изменится.
    тут опять 2 выхода:
    1) сделать первым итемом не имя листа а свой собственный. (если его ещё и назвать "выберите лист", то это будет служить дополнительной подсказкой для пользователя.)

    переписываем self.comboBox.addItems(self.wbr.sheet_names()) на
    self.comboBox.addItems(["выберите лист"] + self.wbr.sheet_names())
    т.к. индексы сместились то и sheet вычисляем с индексом -1:
    sheet = self.wbr.sheet_by_index(list_index-1)
    и придется делать проверку на то что list_index больше нуля. (мы же не хотим читать лист под номером "-1")
    if list_index:
    ваш код.

    вдоволь наигравшись с вашей программой замечаем что comboBox при выборе фаила заполняется но при этом не стирает предыдущие значения.
    исправляем добавляя перед additems
    self.comboBox.clear()

    вроде бы всё хорошо.

    2) более простой способ:
    просто использовать сигнал activated вместо currentIndexChanged тогда оно будет реагировать даже на выбор уже выбранного. Но я всё равно рекомендую проделать операции из первого способа.

    Суммарный код:
    class OpenFile(QtGui.QMainWindow):
        def __init__(self, parent=None):
            QtGui.QMainWindow.__init__(self, parent)
            self.setGeometry(300, 300, 325, 100)
            self.setWindowTitle(self.trUtf8('Выбор файла'))
            self.setWindowIcon(QtGui.QIcon('imageformats\icon.jpeg'))
    
            pButton = QtGui.QPushButton('Открыть файл', self)
            pButton.setGeometry(25, 15, 125, 25)
            self.connect(pButton, QtCore.SIGNAL('clicked()'), self.showDialog)
    
            quit = QtGui.QPushButton('Выход', self)
            quit.setGeometry(175, 15, 125, 25)
            self.connect(quit, QtCore.SIGNAL('clicked()'),
                         QtGui.qApp, QtCore.SLOT('quit()'))
    
            self.comboBox = QtGui.QComboBox(self)
            self.comboBox.setGeometry(QtCore.QRect(25, 55, 125, 25))
            self.comboBox.setObjectName(self.trUtf8("comboBox"))
            self.comboBox.activated.connect(self.slot_list_selected)
    
        def showDialog(self):
            filename = QtGui.QFileDialog.getOpenFileName(self, 'Выбор файла', '*xls')
            self.wbr = xlrd.open_workbook(filename, formatting_info=True)
            self.comboBox.blockSignals(True)
            self.comboBox.clear()
            self.comboBox.addItems(["выберите лист"] + self.wbr.sheet_names())
            self.comboBox.blockSignals(False)
    
    
        def slot_list_selected(self, list_index):
            if list_index:
                # //////////////////Индекс листа///////////////////////
                sheet = self.wbr.sheet_by_index(list_index-1)
                print(list_index)
        
                vals = []
                i = 0
                a = 0
        
                for rows in range(sheet.nrows):
                    vals.append(sheet.row_values(rows))
        
                # /////////////Удаляем из массива шапку Промоактивности//////////////
                for a in range(4):
                    del vals[0]
                    a = +1
        
                file_csv = open('C:\promo.csv', 'w')
        
                for i in range(sheet.nrows - 4):
                    stroka_0 = str(vals[i]).replace('[', '')
                    stroka_1 = stroka_0.replace(',', ';')
                    stroka_2 = stroka_1.replace(']', '')
                    stroka_3 = stroka_2.replace(' ', '')
                    stroka_4 = stroka_3.replace("'", '')
                    stroka_5 = stroka_4.replace(".0", '')
                    file_csv.write(stroka_5 + "\n")
                    i = +1
        
                file_csv.close()
    Ответ написан
    2 комментария
  • Как отобразить в QTableWidget искомую строку в середине видимой области таблицы?

    @Sergey6661313
    scrollToItem(self.tableWidget0.item(vec,i), QtCore.QAbstractItemView.PositionAtCenter)
    пробуй
    Ответ написан
    Комментировать
  • Как в PyQt4 сделать, чтобы поток слышал сигнал от GUI?

    @Sergey6661313
    код не смотрел но:
    self.emit - переводя на русский получается послать сигнал себе.
    self.worker.emit - должно сработать...

    А вообще на до делать по современному (в reference guide отлично расписано, жалко что только по английски. ):
    class MainWindow(QtGui.QMainWindow):
        ...ваша простыня...
        def stop(self):  # остановка
            self.worker.stoping.emit() # да-да просто обрящяемся к сигналу stoping
            self.doneChecking()  # изменяем состояние виджетов гуи
        ... остальные куски вашей простыни...
    
    
    class Worker(QtCore.QObject): 
        stoping = pyqtSignal()   # сообственно наш сигнал. инициализировать нужно именно тут а не в init это важно, но я хз почему. Может ругнутся на то что не видит  pyqtSignal - тут зависит от того как вы импортировали qt и какая у вас версия его. QtCore.pyqtSignal() или QtCore.Qt.pyqtSignal() пробуйте сами короче.
        
        def __init__(self):
            super().__init__() 
            self.stoping.connect(self.stopFlag) # соединяем наш сигнал с вашим методом.
    
        ...остальная часть вашего кода...

    другие сигналы аналогично.
    и последнее мне кажется что в методе run нужно
    while self.exiting:
    иначе через час работы процесс просто завершится. (хотя может так и задумано?)

    и вообще в проверке if not self.exiting: # пока не нажали кнопку Stop.
    если не сделать
    else:
        return

    то выше назначенный цикл for продолжит свою работу просто игнорируя все записи.
    Ответ написан
    Комментировать
  • Как при двойном клике по строке в таблице произвести поиск из другой таблицы?

    @Sergey6661313
    1) #Значение id из dbtable_2 необходимо выяснить до того как вы его вызовете.
    #Значения строки, столбца
        row = mod_inx.row()
        column = mod_inx.column()
    
        #Значение id из dbtable_2
        id_search =  main_window.tableView_1.model().index(row, 2).data()
    нужно поставить в начало функции а не в конец...

    2) запрос это текст вот и операторы используйте как для текста:
    query = "SELECT * FROM dbtable_2 WHERE id = " + str(id_search)
    result_model.setQuery(query)


    3) предлагаю использовать peewee для чтения и записи sqlite таблиц (на хабре есть примеры). Он быстрый и удобный.
    Ответ написан
    3 комментария
  • Как создать новое окно в PyQt5?

    @Sergey6661313
    причина: переменная new_window умирает сразу как заканчивается функция new_form() (почему? во славу Сатаны конечно!)
    Пути решения:

    1) создать какую нибудь глобальную переменную. Но глобальные переменные это плохой тон (незнаю почему) :
    new_window = None
    def new_form():   
        global new_window
        new_window = uic.loadUi("interface2.ui")
        new_window.setWindowTitle("New form")
        new_window.show()


    2) создать переменную глобальный массив окон (так делаю я - это всё ещё "плохой тон" но зато потом можно циклом разом удалить все создаваемые окна например...) :
    мой_список_окон = []
    def new_form():   
        global мой_список_окон
        new_window = uic.loadUi("interface2.ui")
        new_window.setWindowTitle("New form")
        new_window.show()
        мой_список_окон.append(new_window)


    3) назначить new_window дочерю main_window (идиологически правильный вариант):
    def new_form(parent):   
        new_window = uic.loadUi("interface2.ui")
        new_window.setWindowTitle("New form")
        new_window.show()
        new_window.setParent(parent)
    
    import test2
    main_window.pushButton.clicked.connect(lambda: test2.new_form(main_window))


    4) new_window должна быть переменной того обьекта который гарантировано не будет удалён (незнаю насчёт идиалогии... все варианты правильные. ):
    def new_form(parent):   
        parent.new_window = uic.loadUi("interface2.ui")
        parent.new_window.setWindowTitle("New form")
        parent.new_window.show()
    
    
    import test2
    main_window.pushButton.clicked.connect(lambda: test2.new_form(main_window))
    Ответ написан
    3 комментария