Python: Script doesn't run without print - python-2.7

I have written a small executable script. This program only works when I use a print-statement (at the end of the on_start()-method of the QDialog()class). Please, take a look in the on_start()-method of the QDialog-class.
As you can see I create an a task_thread- and work_object-instance. But, when I execute this script without print-statement nothing happens - no Traceback or other error messages.
Where is the bug? I guess the problem is that I create the instances at the local level - I am not sure. How can I fix it?
import sys
from time import sleep
from PyQt4.QtCore import QThread, pyqtSignal, Qt, QStringList, QObject, QTimer
from PyQt4.QtGui import QVBoxLayout, QPushButton, QDialog, QProgressBar, QApplication, \
QMessageBox, QTreeWidget, QTreeWidgetItem, QLabel
def create_items(total):
for elem in range(total):
yield elem
class WorkObject(QObject):
notify_progress = pyqtSignal(object)
fire_label = pyqtSignal(object)
finished = pyqtSignal()
def __init__(self, parent=None):
QObject.__init__(self, parent)
def add_items(self):
total = 190000
x = (total/100*1)
a = x
counter = 0
for element in create_items(10000):
counter += 1
self.notify_progress.emit((element))
self.fire_label.emit((counter))
if counter == x:
x += a
sleep(1)
if not self.keep_running:
self.keep_running = True
break
def run(self):
self.keep_running = True
self.add_items()
def stop(self):
self.keep_running = False
class MyCustomDialog(QDialog):
finish = pyqtSignal()
def __init__(self, parent=None):
QDialog.__init__(self, parent)
layout = QVBoxLayout(self)
self.tree = QTreeWidget(self)
self.label = QLabel(self)
self.pushButton_start = QPushButton("Start", self)
self.pushButton_stopp = QPushButton("Stopp", self)
self.pushButton_close = QPushButton("Close", self)
layout.addWidget(self.label)
layout.addWidget(self.tree)
layout.addWidget(self.pushButton_start)
layout.addWidget(self.pushButton_stopp)
layout.addWidget(self.pushButton_close)
self.pushButton_start.clicked.connect(self.on_start)
self.pushButton_stopp.clicked.connect(self.on_finish)
self.pushButton_close.clicked.connect(self.close)
def fill_tree_widget(self, i):
parent = QTreeWidgetItem(self.tree)
self.tree.addTopLevelItem(parent)
parent.setText(0, unicode(i))
parent.setCheckState(0, Qt.Unchecked)
parent.setFlags(parent.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable)
def on_label(self, i):
self.label.setText("Result: {}".format(i))
def on_start(self):
self.tree.clear()
self.label.clear()
task_thread = QThread(self)
work_object = WorkObject()
work_object.fire_label.connect(self.on_label)
work_object.notify_progress.connect(self.fill_tree_widget)
work_object.finished.connect(task_thread.quit)
self.finish.connect(work_object.stop)
work_object.moveToThread(task_thread)
task_thread.started.connect(work_object.run)
task_thread.finished.connect(task_thread.deleteLater)
timer = QTimer()
# I set the single shot timer on False,
# because I don't want the timer to fires only once,
# it should fires every interval milliseconds
timer.setSingleShot(False)
timer.timeout.connect(work_object.stop)
timer.start(0)
task_thread.start()
print
def on_finish(self):
self.finish.emit()
def main():
app = QApplication(sys.argv)
window = MyCustomDialog()
window.resize(600, 400)
window.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()

You are right, work_object is created as a local instance.
Here is a simple solution:
work_object = WorkObject()
self.work_object = work_object # Add this line

Related

How can i disable the selection highlighted green in table widget using pyqt4

Here is my sample code.I need to remove green highlighted selection in my table widget for that i wrote QtGui.QAbstractItemView.NoSelection but using this line i am not able to move my cursor up,down ,left and right in table widget.Can any one please tell me how to disable the green selection and i want to move my cursor using with arrow keys in keyboard..Please help me..Thank you in advance..
Given below is my code:
import sys
from PyQt4 import QtCore,QtGui
global data_arraylist,count,pushBtnList,lineeditList
class Table_Program(QtGui.QMainWindow ):
def __init__(self,config=None, parent=None):
super(Table_Program, self).__init__(parent)
global data_arraylist,count,pushBtnList,lineeditList
self.scrollArea_left = QtGui.QScrollArea(widgetResizable=True)
self.mainw2 = QtGui.QWidget()
self.mainw2.showFullScreen()
self.scrollArea_left.setWidget(self.mainw2)
self.newvbox = QtGui.QGridLayout(self.mainw2)
self.table = QtGui.QTableWidget()
self.table_item = QtGui.QTableWidgetItem()
self.table.setRowCount(1)
self.table.verticalHeader().hide()
self.table.setColumnCount(4)
self.table.setHorizontalHeaderLabels(("S.no, Item Description,Qty,Rate(Rs:),"",").split(','))
self.newvbox.addWidget(self.table,0,0)
self.table.setColumnWidth(2,170)
self.table.setColumnWidth(3,200)
self.btn1 = QtGui.QPushButton(icon=QtGui.QIcon("./plus1.png"))
self.btn1.setIconSize(QtCore.QSize(30,20))
self.table.setCellWidget(0,0,self.btn1)
self.btn1.clicked.connect(self.insert_rows)
self.table.setItem(0,4,QtGui.QTableWidgetItem(str(" ")))
self.setCentralWidget(self.scrollArea_left)
# QtGui.QShortcut(QtGui.QKeySequence(QtCore.Qt.Key_Up), self, self.moveup)
def insert_rows(self,typ=None):
layout_item = QtGui.QHBoxLayout()
cellWidget = QtGui.QWidget()
self.itemlineedit = QtGui.QLineEdit()
self.itemlineedit.setFrame(False)
self.search_btn = QtGui.QPushButton(icon=QtGui.QIcon('search.png'))
self.search_btn.setIconSize(QtCore.QSize(20,20))
layout_item.addWidget(self.itemlineedit)
layout_item.addStretch()
layout_item.addWidget(self.search_btn)
cellWidget.setLayout(layout_item)
global pushBtnList
ct = self.table.rowCount()
self.table.insertRow(ct-1)
self.btn = QtGui.QPushButton()
self.btn.setIcon(QtGui.QIcon("./delete.png"))
self.btn.setIconSize(QtCore.QSize(30,60))
self.table.setItem(ct-1,0,QtGui.QTableWidgetItem(str(ct)))
self.table.setCellWidget(ct -1,5,self.btn)
index = QtCore.QPersistentModelIndex(self.table.model().index(ct -1, 5))
self.quantybutton = QtGui.QLineEdit()
self.itemlineedit.textChanged.connect(partial(self.product_rate,ct))
completer = QtGui.QCompleter()
self.itemlineedit.setCompleter(completer)
self.model = QtGui.QStringListModel()
self.itemlineedit.resize(100,50)
completer.setModel(self.model)
self.item_rate = QtGui.QLabel()
self.table.setCellWidget(ct-1, 3,self.item_rate)
self.table.setCellWidget(ct-1, 2, self.quantybutton)
self.table.setCellWidget(ct -1, 1, cellWidget)
self.table.setRowHeight(ct-1,50)
self.table.setColumnWidth(1,170)
def get_data(self,model):
model.setStringList(["item1","item2","item3"])
def product_rate(self,text,index):
self.quantybutton.setText("1")
self.item_rate.setText(str("20"))
self.get_data(self.model)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
tb = Table_Program()
tb.show()
tb.resize(600,300)
sys.exit(app.exec_())
A simple solution is to implement a custom QStyle that disables the highlight option in the QTableWidget:
from PyQt4 import QtCore, QtGui
class CustomStyle(QtGui.QCommonStyle):
def drawPrimitive(self, element, option, painter, widget):
if element == QtGui.QStyle.PE_PanelItemViewItem:
option.state &= ~QtGui.QStyle.State_Selected
super(CustomStyle, self).drawPrimitive(element, option, painter, widget)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
w = QtGui.QTableWidget(5, 4)
w.setStyle(CustomStyle()) # <--- set style
w.show()
sys.exit(app.exec_())

QThread and pyqtgraph no performance improvement

I am trying to do a multigraph window for plotting different data using pyqtgraph. I have a working version with no threads using timers for getting the data. I also tried a threaded version but it seems to have no performance boost when use htop for visually inspecting the CPU Usage.
I am new to GUIs and Threads so I followed this code that I saw in a youtube tutorial. It uses a QThread to get the CPU usage using psutil.cpu_percent in intervals of 0.1 seconds and then updates a progress bar.
import sys
from PyQt4 import QtCore
from PyQt4 import QtGui
import progress
import sysinfo
class MainUIClass(QtGui.QMainWindow, progress.Ui_MainWindow):
def __init__(self, parent = None):
super(MainUIClass, self).__init__(parent)
self.setupUi(self)
self.threadClass = ThreadClass()
self.threadClass.start()
self.connect(self.threadClass, QtCore.SIGNAL('CPU_VALUE'),
self.updateProgressBar)
def updateProgressBar(self, val):
self.progressBar.setValue(val)
class ThreadClass(QtCore.QThread):
def __init__(self, parent = None):
super(ThreadClass, self).__init__(parent)
def run(self):
while 1:
val = sysinfo.getCPU()
self.emit(QtCore.SIGNAL('CPU_VALUE'), val)
if __name__ == '__main__':
a = QtGui.QApplication(sys.argv)
app = MainUIClass()
app.show()
a.exec_()
I tried using cProfile for comparing performance but it throws lot of stuff that couldn't read, so I use the example of the progress bar to average the cpu usage after 10 seconds. Sorry if my measure performance method is so poor.
My two codes for benchmarking are
Threaded Version with a very consistent average CPU Usage of 64%:
import sys
from pyqtgraph.Qt import QtCore
from pyqtgraph.Qt import QtGui
import pyqtgraph as pg
import numpy as np
import time
class GraphWindow_Thread(pg.GraphicsWindow):
def __init__(self, rows, cols, titles):
super(GraphWindow_Thread, self).__init__()
# Code to draw the GUI
self.rows = rows
self.cols = cols
self.titles = titles
self.plots = [] # List of PlotItems
self.curves = [] # List of PlotDataItems in each PlotItem
for i in range(self.rows):
for j in range(self.cols):
p = self.addPlot()
self.plots.append(p)
if titles != [] or len(titles) == 1:
p.setLabel('left', self.titles[i+j+1])
p.setDownsampling(mode='peak')
p.setClipToView(True)
pp = p.plot(pen=(155, 255, 50))
pp1 = p.plot(pen=(55, 130, 255))
self.curves.append((pp, pp1))
self.nextRow()
# Thread to get the data and redraw plots
self.thread_graph = DataThread()
self.thread_graph.start()
self.connect(self.thread_graph, QtCore.SIGNAL('DATA_VALUE'),
self.update_plots)
def set_titles(self, titles):
for i, p in enumerate(self.plots):
p.setLabel('left', titles[i])
def update_plots(self, data, dataD):
for curve in self.curves:
curve[0].setData(data)
curve[1].setData(dataD)
class DataThread(QtCore.QThread):
def __init__(self, parent = None):
super(DataThread, self).__init__(parent)
def run(self):
while 1:
data = np.random.random((30,))
dataD = np.random.random((30,))
self.emit(QtCore.SIGNAL('DATA_VALUE'), data, dataD)
time.sleep(.1)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
gui = GraphWindow_Thread(2,3,[])
gui.show()
app.exec_()
No Thread Version with a very consistent average CPU Usage of 65%:
import sys
from pyqtgraph.Qt import QtCore
from pyqtgraph.Qt import QtGui
import pyqtgraph as pg
import numpy as np
import time
class GraphWindow(pg.GraphicsWindow):
def __init__(self, rows, cols, titles):
super(GraphWindow, self).__init__()
# Code to draw the GUI
self.rows = rows
self.cols = cols
self.titles = titles
self.plots = [] # List of PlotItems
self.curves = [] # List of PlotDataItems in each PlotItem
for i in range(self.rows):
for j in range(self.cols):
p = self.addPlot()
self.plots.append(p)
if titles != [] or len(titles) == 1:
p.setLabel('left', self.titles[i+j+1])
p.setDownsampling(mode='peak')
p.setClipToView(True)
pp = p.plot(pen=(155, 255, 50))
pp1 = p.plot(pen=(55, 130, 255))
self.curves.append((pp, pp1))
self.nextRow()
# Timer to redraw plots
timer = QtCore.QTimer(self)
self.connect(timer, QtCore.SIGNAL('timeout()'),self.update_plots)
timer.start(100)
def set_titles(self, titles):
for i, p in enumerate(self.plots):
p.setLabel('left', titles[i])
def update_plots(self):
np.random.seed()
data = np.random.random((30,))
dataD = np.random.random((30,))
for curve in self.curves:
curve[0].setData(data)
curve[1].setData(dataD)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
gui = GraphWindow(2,3,[])
gui.show()
app.exec_()
The full app is meant to be a window with multiple tabs, each one with a GraphWindow in which each graph uses a Thread for plotting different data.
What am I missing? Why my threaded version does not represent a performance improvement?

Tkinter assign buttons to entries in dynamically created widgets

How can I access an Entry content with pressing the corresponding Button in dynamically created widgets?
Below is the best I come up with so far. Thank you for any help.
from Tkinter import *
class App(object):
def __init__(self, master):
self.master = master
self.mf = Frame(self.master)
self.l = ["white", "red", "blue", "brown"]
self.font = ("Arial", 30)
self.c, self.r = 1, 0
self.cc, self.rr = 0, 0
self.bel = []
for c in self.l:
action = self.print_entry
self.e = Entry(self.mf, bg=c, width=10, font=self.font)
self.e.grid(row=self.r, column=self.c)
self.b = Button(self.mf, bg=c, text=c, font=self.font)
self.b.grid(row=self.rr, column=self.cc)
self.b.config(command=action)
self.bel.append((self.b, self.e))
self.rr += 1
self.r += 1
self.mf.pack()
def print_entry(self): # this function prints the content of the entry
pass
def main():
root = Tk()
display = App(root)
root.mainloop()
if __name__=="__main__":
main()
You can pass a reference to the entry widget into the command, using lambda or functools.partial. For example:
self.b.config(command= lambda entry=self.e: action(entry))
...
def print_entry(self, entry):
print("the entry is '%s'" % entry.get())
By the way, using self.b and self.e is pointless, since those variables will only ever hold references to the last button and last entry. You should either use a local variable, and/or append the values to a list.

Why is the tkinter window blank?

My code uses pygame in order to play all MIDI files within its location, however A Tkinter Slider Window is supposed to show up but it doesn't. And I don't know why.
import os,fnmatch,pygame
import Tkinter as tk
pygame.mixer.init()
root = tk.Tk()
List = []
Song = 0
def getThrottle(event):
Volume = Throttle.get()
print "|"*((Volume)*50/100)
def Update():
List = []
for file in os.listdir('.'):
if fnmatch.fnmatch(file, '*.mid'):
List.append(file)
return List
class Slider:
def _Init_(self,root):
self.Throttle = self.Scale(master, from_=0, to=100, tickinterval=10, length=200, orient=HORIZONTAL, command=getThrottle)
self.Throttle.set(0)
self.Throttle.pack()
List = Update()
S = Slider()
root.mainloop()
print List
while True:
while Song <= len(List):
pygame.mixer.music.load(List[Song])
pygame.mixer.music.play(1)
while pygame.mixer.music.get_busy() == True:
List=Update()
Song = 3
Song = 0

Using Python Tkinter .config() method

I am trying to use the Python Tkinter .config() method to update some message text. I can't get it to work. What might I be doing wrong (see the update_message method):
#!/usr/bin/python
import alsaaudio as aa
import audioop
import Tkinter as tk
import tkFont
import threading
import Queue
# styles
BACKROUND_COLOR = '#000000'
TYPEFACE = 'Unit-Bold'
FONT_SIZE = 50
TEXT_COLOR = '#777777'
TEXTBOX_WIDTH = 400
# text
TITLE = 'listen closely'
SCORE_MESSAGE = 'your score:\n '
END_MESSAGE = 'too loud!\ntry again'
# configuration
DEVICE = 'hw:1' # hardware sound card index
CHANNELS = 1
SAMPLE_RATE = 8000 # Hz // 44100
PERIOD = 256 # Frames // 256
FORMAT = aa.PCM_FORMAT_S8 # Sound format
NOISE_THRESHOLD = 3
class Display(object):
def __init__(self, parent, queue):
self.parent = parent
self.queue = queue
self._geom = '200x200+0+0'
parent.geometry("{0}x{1}+0+0".format(
parent.winfo_screenwidth(), parent.winfo_screenheight()))
parent.overrideredirect(1)
parent.title(TITLE)
parent.configure(background=BACKROUND_COLOR)
parent.displayFont = tkFont.Font(family=TYPEFACE, size=FONT_SIZE)
self.process_queue()
def process_queue(self):
try:
score = self.queue.get(0)
self.print_message(score)
except Queue.Empty:
pass
self.parent.after(100, self.update_queue)
def update_queue(self):
try:
score = self.queue.get(0)
self.update_message(score)
except Queue.Empty:
pass
self.parent.after(100, self.update_queue)
def print_message(self, messageString):
print 'message', messageString
displayString = SCORE_MESSAGE + str(messageString)
self.message = tk.Message(
self.parent, text=displayString, bg=BACKROUND_COLOR,
font=self.parent.displayFont, fg=TEXT_COLOR, width=TEXTBOX_WIDTH, justify="c")
self.message.place(relx=.5, rely=.5, anchor="c")
def update_message(self, messageString):
print 'message', messageString
displayString = SCORE_MESSAGE + str(messageString)
self.message.config(text=displayString)
def setup_audio(queue, stop_event):
data_in = aa.PCM(aa.PCM_CAPTURE, aa.PCM_NONBLOCK, 'hw:1')
data_in.setchannels(2)
data_in.setrate(44100)
data_in.setformat(aa.PCM_FORMAT_S16_LE)
data_in.setperiodsize(256)
while not stop_event.is_set():
# Read data from device
l, data = data_in.read()
if l:
# catch frame error
try:
max_vol = audioop.rms(data, 2)
scaled_vol = max_vol // 4680
print scaled_vol
if scaled_vol <= 3:
# Too quiet, ignore
continue
queue.put(scaled_vol)
except audioop.error, e:
if e.message != "not a whole number of frames":
raise e
def main():
root = tk.Tk()
queue = Queue.Queue()
window = Display(root, queue)
stop_event = threading.Event()
audio_thread = threading.Thread(target=setup_audio,
args=[queue, stop_event])
audio_thread.start()
try:
root.mainloop()
finally:
stop_event.set()
audio_thread.join()
pass
if __name__ == '__main__':
main()
I don't want to be laying down a new message every time I update. If the .config() doesn't work, is there another method to update the text configuration of the message?
I would use string variables, first create your string variable then set it to want you want it to display at the start next make your object and in text put the sting variable then when you want to change the text in the object change the string variable.
self.messaget = StringVar()
self.messaget.set("")
self.message = tk.Message(
self.parent, textvariable=self.messaget, bg=BACKROUND_COLOR,
font=self.parent.displayFont, fg=TEXT_COLOR,
width=TEXTBOX_WIDTH, justify="c").grid()
#note renember to palce the object after you have created it either using
#.grid(row = , column =) or .pack()
#note that it is textvariable instead of text if you put text instead it will run but
#but will show PY_Var instead of the value of the variable
edit
to change the text without recreating the object you do the name of the string variable you have used and .set
self.messaget.set("hi")