Python+Glade Set Label text - python-2.7

I have a little python script with a Gladefile but my code i not doing was i wanted it to.
There several issues that i can't solve. Just trying to get a date/time written on my label "DK_Tid".
But I get an error:
self.DK_Tid.set_text(dk_time)
NameError: global name 'self' is not defined
And when i have tried to move the thread out of class, there is no print, but window is showed. All sort of variation i've tried, but now i'm stuck.
No mather what i do, it won't work.
Can anyone help me?
#!/usr/bin/env python
#
# Time test deppends on test.glade
import sys, time, thread, gi
gi.require_version('Gtk', '3.0')
from gi.repository import GObject,Gtk as Gtk
gi.require_version('GdkX11', '3.0')
from gi.repository import GdkX11
from datetime import datetime, timedelta
class GTK_Main(object):
def __init__(self):
self.gladefile = ("test.glade")
self.builder = Gtk.Builder()
self.builder.add_from_file(self.gladefile)
self.builder.connect_signals(self)
## Create objects by name from glade
self.window = self.builder.get_object("window")
self.DK_Tid = builder.get_object("DK_Tid")
self.window.show_all()
# Create handles
def on_window_destroy(self, object, data=None):
Gtk.main_quit()
def UTC_time():
now = datetime.now()
new_time = now + timedelta(hours=0, minutes=0, seconds=1)
while True:
if new_time < datetime.now():
dk_time = time.strftime("%d %B %Y %H:%M:%S")
self.DK_Tid.set_text(dk_time)
print dk_time
now = new_time
new_time = now + timedelta(hours=0, minutes=0, seconds=1)
thread.start_new_thread(UTC_time())
GObject.threads_init()
GTK_Main()
Gtk.main()

Solution found by myself. :-)
Gtk is strange sometimes.
I think that i needed to put in after the if function:
while Gtk.events_pending():
Gtk.main_iteration()
But is quite some time ago i made that script.

Related

Python Tkinter: destroy() my Toplevel() window

I don't understand what I'm doing wrong.
I'm trying to create a log in window. When you click Log in, I want to to go do stuff and after that close out and go to the main GUI.
I found a bunch of stuff online that I can't make heads or tails of. I do not want to cut and paste other people's code which I do not fully understand.
So I'd like to understand what I'm doing wrong here. To start I created a destroyWindow() method which I call from the button as just a starting point.
There is a scope issue where loginWindow does not exist within its own class. I thought the class application would get around the scope issue. I tried using 'self.' but to no avail. I tried random things I saw in other people's code. Please can someone pinpoint what I'm missing here? I get
NameError: global name 'loginWindow' is not defined
#!/Usr/bin/Python
import Tkinter,tkFileDialog,tkMessageBox
from Tkinter import *
from tkFileDialog import *
import sys, time, datetime
import pathlib
from pathlib import * #makes it really easy to travers folders if needed.
mainWindow = Tk()
mainWindow.wm_title("my prog")
mainWindow.wm_iconbitmap('fb_logo_sm.ico')
mainFrame = Frame(mainWindow)
mainFrame.grid(padx=10,pady=10)
class loginWindowClass():
def __init__(self):
loginWindow = Tkinter.Toplevel()
loginWindow.configure(bg='#22BEF2')
loginWindowFrame = Frame(loginWindow,bg='#22BEF2')
loginWindowFrame.grid(padx=90,pady=50)
loginWindow.wm_title("log in")
loginWindow.wm_iconbitmap('my.ico')
usernameLable = Tkinter.Label(loginWindowFrame,text="User Name",fg='#FFFFFF',bg='#22BEF2')
usernameLable.grid(row=1,column=2,padx=(0,5),sticky=W+S)
usernameField = Entry(loginWindowFrame)
usernameField.config(width=24)
usernameField.grid(row=2,column=2)
passwordLable =Tkinter.Label(loginWindowFrame,text="Password",fg='#FFFFFF',bg='#22BEF2')
passwordLable.grid(row=3,column=2,sticky=W+S)
passwordField = Entry(loginWindowFrame)
passwordField.config(width=24)
passwordField.grid(row=4,column=2)
loginButton = Button(loginWindowFrame, text='Log In', height=1, width=20, wraplength=100, fg='white',bg='#bbbbbb',command=self.destroyWindow).grid(row=5,column=2,pady=(10,0))
def destroyWindow(self):
loginWindow.destroy()
logwin = loginWindowClass()
mainWindow.mainloop()
Ah. 'self.' is the answer indeed.
I did not apply it everywhere. Here is the solution
#!/Usr/bin/Python
import Tkinter,tkFileDialog,tkMessageBox
from Tkinter import *
from tkFileDialog import *
import sys, time, datetime
import pathlib
from pathlib import * #makes it really easy to travers folders if needed.
mainWindow = Tk()
mainWindow.wm_title("my prog")
mainWindow.wm_iconbitmap('fb_logo_sm.ico')
mainFrame = Frame(mainWindow)
mainFrame.grid(padx=10,pady=10)
class loginWindowClass():
def __init__(self):
self.loginWindow = Tkinter.Toplevel()
self.loginWindow.configure(bg='#22BEF2')
loginWindowFrame = Frame(self.loginWindow,bg='#22BEF2')
loginWindowFrame.grid(padx=90,pady=50)
self.loginWindow.wm_title("log in")
self.loginWindow.wm_iconbitmap('my.ico')
usernameLable = Tkinter.Label(loginWindowFrame,text="User Name",fg='#FFFFFF',bg='#22BEF2')
usernameLable.grid(row=1,column=2,padx=(0,5),sticky=W+S)
usernameField = Entry(loginWindowFrame)
usernameField.config(width=24)
usernameField.grid(row=2,column=2)
passwordLable =Tkinter.Label(loginWindowFrame,text="Password",fg='#FFFFFF',bg='#22BEF2')
passwordLable.grid(row=3,column=2,sticky=W+S)
passwordField = Entry(loginWindowFrame)
passwordField.config(width=24)
passwordField.grid(row=4,column=2)
loginButton = Button(loginWindowFrame, text='Log In', height=1, width=20, wraplength=100, fg='white',bg='#bbbbbb',command=self.destroyWindow).grid(row=5,column=2,pady=(10,0))
def destroyWindow(self):
self.loginWindow.destroy()
logwin = loginWindowClass()
mainWindow.mainloop()

Why is pyplot having issues with PyQt4's QThread?

I am designing a gui that creates multiple QThreads to be activated. Each thread creates an excel workbook with Pandas Excelwriter and creates a heatmap using seaborn and saves that heatmap (for later use by the user for whatever) and then places it into the excel workbook.
I believe the error is that pyplot is not made into its own instance for the thread that is created..rather a resource that all threads are pointing to..if I run just one thread, there is no issue...two or more threads..in this example 4, there are internal pyplot errors pointing to dictionary size change occurring.
The issue I'm having is when pyplot is put into play. Do I have to do something specific to pyplot like I had to for getting the right backend for matplotlib? I thought the changes I made for matplotlib is inherent to pyplot?
---main.py---
import sys
from MAIN_GUI import *
from PyQt4 import QtGui, QtCore
from excel_dummy import *
df1 = pd.DataFrame(np.array([[1,22222,33333],[2,44444,55555],[3,44444,22222],[4,55555,33333]]),columns=['hour','input','out'])
df2 = pd.DataFrame(np.array([[1,22233,33344],[2,44455,55566],[3,44455,22233],[4,55566,33344]]),columns=['hour','input','out'])
df3 = pd.DataFrame(np.array([[1,23456,34567],[2,98765,45674],[3,44444,22222],[4,44455,34443]]),columns=['hour','input','out'])
df4 = pd.DataFrame(np.array([[1,24442,33443],[2,44444,54455],[3,45544,24442],[4,54455,33443]]),columns=['hour','input','out'])
df_list = [df1,df2,df3,df4]
if __name__=="__main__":
app = QtGui.QApplication(sys.argv)
class MAIN_GUI(QtGui.QMainWindow):
def __init__(self):
super(MAIN_GUI, self).__init__()
self.uiM = Ui_MainWindow()
self.uiM.setupUi(self)
self.connect(self.uiM.updateALL_Button,QtCore.SIGNAL('clicked()'),self.newThread)
def newThread(self):
count = 0
for df in df_list:
count += 1
Excelify = excelify(df,count)
self.connect(Excelify,QtCore.SIGNAL('donethread(QString)'),(self.done))
Excelify.start()
def done(self):
print('done')
main_gui = MAIN_GUI()
main_gui.show()
main_gui.raise_()
sys.exit(app.exec_())
---excel_dummy.py---
import pandas as pd
import numpy as np
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import QThread
import time
import matplotlib as mpl
mpl.use('Agg')
from matplotlib.backends.backend_agg import FigureCanvas
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
import seaborn.matrix as sm
class excelify(QThread):
def __init__(self,df,count):
QThread.__init__(self)
self.df = df
self.count = count
def run(self):
heatit = self.heatmap()
self.emit(QtCore.SIGNAL('donethread(QString)'),'')
def heatmap(self):
dfu = pd.DataFrame(self.df.groupby([self.df.input,self.df.hour]).size())
dfu.reset_index(inplace=True)
dfu.rename(columns={'0':'Count'})
dfu.columns=['input','hour','Count']
dfu_2 = dfu.copy()
mask=0
fig = Figure()
ax = fig.add_subplot(1,1,1)
fig.set_canvas(FigureCanvas(fig))
df_heatmap = dfu_2.pivot('input','hour','Count').fillna(0)
sm.heatmap(df_heatmap,ax=ax,square=True,annot=False,mask=mask)
plt.ylabel('ID')
plt.xlabel('Hour')
plt.title('heatmap for df' + str(self.count))
plt.savefig(path + '/' + 'heat' + str(self.count) + '.png')
plt.close()
---MAIN_GUI.py---
from PyQt4 import QtCore,QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.unicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName(_fromUtf8("MainWindow"))
MainWindow.resize(320,201)
self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
self.updateALL_Button = QtGui.QPushButton(self.centralwidget)
self.updateALL_Button.setGeometry(QtCore.QRect(40,110,161,27))
self.updateALL_Button.setFocusPolicy(QtCore.Qt.NoFocus)
self.updateALL_Button.setObjectName(_fromUtf8("Options_updateALL_Button"))
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtGui.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 320, 24))
self.menubar.setObjectName(_fromUtf8("menubar"))
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtGui.QStatusBar(MainWindow)
self.statusbar.setObjectName(_fromUtf8("statusbar"))
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self,MainWindow):
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
self.updateALL_Button.setText(_translate("MainWindow", "updateALL", None))
While the code in the question is still not really a minimal example (some undefined variable) it is much clearer, where the problem lies.
First, one problem might be that the MAIN_GUI class looses a reference to the thread, such that it will be garbage collected before it can finish. One can prevent this by just putting all threads in a list. [See MAIN_GUI code below]
Second, you cannot use pyplot directly to operate on different figures at once. Or in other words, how should pyplot know in which figure to place the ylabel set by plt.ylabel('ID') if there exist several at the same time?
The way to solve this, is to create different figures and only work within those figures using the object oriented approach. [See excelify code below]
Here is the relevant part of the code, where I also changed the signal to return the plot number for easier debugging.
MAIN_GUI:
class MAIN_GUI(QtGui.QMainWindow):
def __init__(self):
super(MAIN_GUI, self).__init__()
self.uiM = Ui_MainWindow()
self.uiM.setupUi(self)
self.connect(self.uiM.updateALL_Button,QtCore.SIGNAL('clicked()'),self.newThread)
self.threats=[]
def newThread(self):
count = 0
for df in df_list:
count += 1
Excelify = excelify(df,count)
self.connect(Excelify,QtCore.SIGNAL('donethread(int)'),(self.done))
# appending all threats to a class attribute,
# such that they will persist and not garbage collected
self.threats.append(Excelify)
Excelify.start()
def done(self, val=None):
print('done with {nr}'.format(nr=val))
excelify:
class excelify(QThread):
def __init__(self,df,count):
QThread.__init__(self)
self.df = df
self.count = count
def run(self):
heatit = self.heatmap()
self.emit(QtCore.SIGNAL('donethread(int)'),self.count)
def heatmap(self):
print ("{nr} started".format(nr=self.count) )
dfu = pd.DataFrame(self.df.groupby([self.df.input,self.df.hour]).size())
dfu.reset_index(inplace=True)
dfu.rename(columns={'0':'Count'})
dfu.columns=['input','hour','Count']
dfu_2 = dfu.copy()
mask=0
# create a figure and only work within this figure
# no plt.something inside the threat
fig = Figure()
ax = fig.add_subplot(1,1,1)
fig.set_canvas(FigureCanvas(fig))
df_heatmap = dfu_2.pivot('input','hour','Count').fillna(0)
sm.heatmap(df_heatmap,ax=ax,square=True,annot=False,mask=mask)
ax.set_ylabel('ID')
ax.set_xlabel('Hour')
ax.set_title('heatmap for df' + str(self.count))
fig.savefig( 'heat' + str(self.count) + '.png')
fig.clear()
del fig

How to put dates on the x qwtplot axis in python?

I visited tons of pages in the internet but only have examples in C and I dont understand how to make this in python. Can someone helpme.
I use Pyqt designer and Python 2.7. I need plot data whith dates on a GUI using qwtplot.
you need a QwtScaleDraw class e.g.:
class TimeScaleDraw(QwtScaleDraw):
def __init__(self, baseTime, *args):
QwtScaleDraw.__init__(self, *args)
self.baseTime = baseTime
def label(self, value):
upTime = self.baseTime.addSecs(int(value))
return QwtText(upTime.toString())
then you modify your x axis with this code:
self.setAxisScaleDraw(
QwtPlot.xBottom, TimeScaleDraw(self.cpuStat.upTime()))
where self's base class is QwtPlot. cpuStat.upTime() returns a QTime instance. value represents one of your time data points. This code is from the cpuDemo example code.
To get this example cpuDemo working with python xy 2.7. make these changes to the imported modules:
import os
import sys
import numpy as np
from PyQt4.QtGui import (QApplication, QColor, QBrush, QWidget, QVBoxLayout,
QLabel)
from PyQt4.QtCore import QRect, QTime
from PyQt4.QtCore import Qt
from PyQt4.Qwt5 import (QwtPlot, QwtPlotMarker, QwtScaleDraw, QwtLegend, QwtPlotCurve,
QwtPlotItem, QwtText)#, QwtLegendData
then comment out all legend lines.
I adopted this code to use the QDateTime class. Here is a snippet:
from PyQt4 import QtCore, QtGui, Qt
from PyQt4 import Qwt5
class TimeScaleDraw(Qwt5.QwtScaleDraw):
def __init__(self, *args):
Qwt5.QwtScaleDraw.__init__(self,unixBaseTime *args)
self.basetime=unixBaseTime
self.fmt='h:mm\nd-MMM-yyyy'
def label(self, value):
dt = QtCore.QDateTime.fromMSecsSinceEpoch((value+self.basetime))
return Qwt5.QwtText(dt.toString(self.fmt))
...
class Ui_TabWidget(object):
def setupUi(self, TabWidget):
self.qwtPlot = Qwt5.QwtPlot()
self.qwtPlot.setAxisScaleDraw(Qwt5.QwtPlot.xBottom, TimeScaleDraw(unixBaseTime))
admire pretty picture

making a function staticmethod in python is confusing

Hi I have a GUI written using Tkinter and the code template is as follows. My question is PyCharm gives me warnings on my functions (def func1, def func2) that they are static. To get rid of the warnings I placed #staticmethod above the functions. What does this do and is it necessary?
# Use TKinter for python 2, tkinter for python 3
import Tkinter as Tk
import ctypes
import numpy as np
import os, fnmatch
import tkFont
class MainWindow(Tk.Frame):
def __init__(self, parent):
Tk.Frame.__init__(self,parent)
self.parent = parent
self.parent.title('BandCad')
self.initialize()
#staticmethod
def si_units(self, string):
if string.endswith('M'):
num = float(string.replace('M', 'e6'))
elif string.endswith('K'):
num = float(string.replace('K', 'e3'))
elif string.endswith('k'):
num = float(string.replace('k', 'e3'))
else:
num = float(string)
return num
if __name__ == "__main__":
# main()
root = Tk.Tk()
app = MainWindow(root)
app.mainloop()
You can also turn off that inspection so that PyCharm doesn't warn you. Preferences -> Editor -> Inspections. Note that the inspection appears in the JavaScript section as well as the Python section.
You are right about #staticmethod being confusing. It is not really needed in Python code and in my opinion should almost never by used. Instead, since si_units is not a method, move it out of the class and remove the unused self parameter. (Actually, you should have done that when adding #staticmethod; the posted code will not work right with 'self' left in.)
Unless one has forgotten to use 'self' when it needs to be used, this is (or at least should be) the intent of the PyCharm warning. No confusion, no fiddling with PyCharm settings.
While you are at it, you could condense the function and make it easily extensible to other suffixes by using a dict.
def si_units(string):
d = {'k':'e3', 'K':'e3', 'M':'e6'}
end = string[-1]
if end in d:
string = string[:-1] + d[end]
return float(string)
for f in ('1.5', '1.5k', '1.5K', '1.5M'): print(si_units(f))

Proper way to pass variables within a tkinter GUI

I am trying to write a simple GUI to plot data from a csv file, which I read into a pandas DataFrame. I am completely new to GUI programming, and I am having a hard time getting my head around event-driven setups like Tkinter.
As a simple exercise, I want to set up a couple of buttons, one to open a file and read in the DataFrame, and another to print out the resulting DataFrame. My first naive attempt didn't work:
import pandas as pd
import tkFileDialog
import Tkinter as tk
def open_events_db():
file_path_string = tkFileDialog.askopenfilename()
eventsdb = pd.read_csv(file_path_string,encoding='utf-8')
return eventsdb
def print_events_db(eventsdb):
print eventsdb
def main():
root=tk.Tk()
eventsdb = tk.Button(text='File Open', command=open_events_db).pack(fill=tk.X)
tk.Button(text='Print DB', command=lambda:print_events_db(eventsdb)).pack(fill=tk.X)
tk.mainloop()
if __name__=="__main__":
main()
I can read in the file fine, and open it, but in hindsight obviously I can't return eventsdb from the file open button and have it as an argument to the print button.
I don't think it's unreasonable to have buttons that operate on that DB, though, so what is the proper way to pass variables around within the GUI?
Functions called from buttons and event handers don't return their data. Instead, they must set global variables or class attributes.
def open_events_db():
global eventsdb
file_path_string = tkFileDialog.askopenfilename()
eventsdb = pd.read_csv(file_path_string,encoding='utf-8')
def print_events_db():
global eventsdb
print eventsdb
...
tk.Button(text='Print DB', command=print_events_db).pack(fill=tk.X)
It's generally considered poor programming to rely on global variables. Since python is an object oriented language, it makes sense to write your app as a class. You would then use instance attributes rather than global variables.
import Tkinter as tk
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
open_button = tk.Button(text='File Open', command=self.open_events_db)
print_button = tk.Button(text='Print DB', command=self.print_events_db)
open_button.pack(fill=tk.X)
print_button.pack(fill=tk.X)
def open_events_db(self):
file_path_string = tkFileDialog.askopenfilename()
self.eventsdb = pd.read_csv(file_path_string,encoding='utf-8')
def print_events_db():
print self.eventsdb
def main():
root=tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()
if __name__=="__main__":
main()