Related
SOLUTION
Remove the channel and associated code
Add a new update function inside the window class which takes the new shapes as a parameter
modify the initialisation of the class
call the update function
Modifications for the solution
Apologies, but the diff markdown doesn't seem to be displaying properly, hopefully you should still get an idea of how the solution works
Window class
class Window(Gtk.Window):
- __gsignals__ = {
- 'update_signal': (GObject.SIGNAL_RUN_FIRST, None,
- ())
- }
-
- def do_update_signal(self):
- print("UPDATE SIGNAL CALLED")
- self.shapes = self.shapes_channel.read()
- print("Num new shapes:", len(self.shapes))
- self.show_all()
in the class method init_ui
self.connect("delete-event", Gtk.main_quit)
+ self.show_all()
+ a = self.darea.get_allocation()
+ print (a.x, a.y, a.width, a.height)
+ self.img = cairo.ImageSurface(cairo.Format.RGB24, a.width, a.height)
a new class method update_shapes
+ def update_shapes(self, shapes):
+ self.shapes = shapes
+ cr = cairo.Context(self.img)
+ self.draw_background(cr)
+ for shape in self.shapes:
+ shape.draw(cr)
+ self.darea.queue_draw()
+ return True
Main code
- shapes_channel = Channel()
iter_num = 0
- def optimize(chan, prob, signaller):
+ def optimize(prob, signaller):
def print_iter_num(xk):
global iter_num
iter_num += 1
prob.update_positions(xk)
prob.update_grads(jacobian(xk))
new_shapes = convert_grid(prob.grid, building_size=1.0/GRID_SIZE)
- chan.write(new_shapes)
- signaller.emit("update_signal")
+ GLib.idle_add(signaller.update_shapes, new_shapes)
print("Iteration", iter_num, "complete...")
try:
sol = minimize(objective, x0, bounds = all_bounds, constraints=constraints, options={'maxiter': MAX_ITER, 'disp': True}, callback=print_iter_num, jac=jacobian)
prob.update_positions(sol.x)
except Exception as e:
print("ran into an error", e)
- window = new_window(shapes_channel=shapes_channel)
+ window = new_window()
- x = threading.Thread(target=optimize, args=(shapes_channel, optim_problem, window))
+ x = threading.Thread(target=optimize, args=(optim_problem, window))
x.start()
window.run()
QUESTION
Window class
import cairo
import gi
import math
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GObject
class Line():
def __init__(self, start, end, thickness, colour):
self.start = start
self.end = end
self.thickness = thickness
self.colour = colour
def draw(self, cr):
cr.move_to(*self.start)
cr.line_to(*self.end)
cr.set_source_rgba(*self.colour)
cr.set_line_width(self.thickness)
cr.stroke()
class Polygon():
def __init__(self, points, line_colour, line_thickness, fill_colour=None):
self.points = points # points should be an iterable of points
self.line_colour = line_colour
self.line_thickness = line_thickness
self.fill_colour = fill_colour
def draw(self, cr):
cr.move_to(*self.points[0])
for point in self.points[1:]:
cr.line_to(*point)
cr.close_path()
cr.set_source_rgba(*self.line_colour)
cr.set_line_width(self.line_thickness)
cr.stroke()
if self.fill_colour is not None:
cr.move_to(*self.points[0])
for point in self.points[1:]:
cr.line_to(*point)
cr.close_path()
cr.set_source_rgba(*self.fill_colour)
cr.fill()
class Window(Gtk.Window):
__gsignals__ = {
'update_signal': (GObject.SIGNAL_RUN_FIRST, None,
())
}
def do_update_signal(self):
print("UPDATE SIGNAL CALLED")
self.shapes = self.shapes_channel.read()
print("Num new shapes:", len(self.shapes))
self.show_all()
def __init__(self, shapes_channel, window_size, background_colour=(1, 1, 1, 1), title="GTK window"):
super(Window, self).__init__()
self.width = window_size[0]
self.height = window_size[1]
self.background_colour = background_colour
self.title = title
self.shapes = []
self.shapes_channel = shapes_channel
self.init_ui()
def init_ui(self):
darea = Gtk.DrawingArea()
darea.connect("draw", self.on_draw)
self.add(darea)
self.set_title(self.title)
self.resize(self.width, self.height)
self.set_position(Gtk.WindowPosition.CENTER)
self.connect("delete-event", Gtk.main_quit)
def draw_background(self, cr: cairo.Context):
cr.scale(self.width, self.height)
cr.rectangle(0, 0, 1, 1) # Rectangle(x0, y0, x1, y1)
cr.set_source_rgba(*self.background_colour)
cr.fill()
def on_draw(self, wid, cr: cairo.Context):
self.draw_background(cr)
for shape in self.shapes:
shape.draw(cr)
def run(self):
Gtk.main()
def new_window(shapes_channel,
window_size=(1000, 1000),
background_colour=(1,1,1,1),
title="3yp"):
return Window(shapes_channel,
window_size=window_size,
background_colour=background_colour,
title=title)
I'm trying to run a window that can draw the shapes I've defined (Lines and Polygons).
It worked fine before when I supplied it a list of shapes and ran it at the end of my application
However, I am trying to add interactivity and have it redraw a list of shapes when the update_signal gets called and a list of new shapes get passed along the shapes_channel that is part of the constructor.
Main Code
Here is the relevant bits from my main code:
shapes_channel = Channel()
iter_num = 0
def optimize(chan, prob, signaller):
def print_iter_num(xk):
global iter_num
iter_num += 1
prob.update_positions(xk)
prob.update_grads(jacobian(xk))
new_shapes = convert_grid(prob.grid, building_size=1.0/GRID_SIZE)
chan.write(new_shapes)
signaller.emit("update_signal")
print("Iteration", iter_num, "complete...")
try:
sol = minimize(objective, x0, bounds = all_bounds, constraints=constraints, options={'maxiter': MAX_ITER, 'disp': True}, callback=print_iter_num, jac=jacobian)
prob.update_positions(sol.x)
except Exception as e:
print("ran into an error", e)
window = new_window(shapes_channel=shapes_channel)
x = threading.Thread(target=optimize, args=(shapes_channel, optim_problem, window))
x.start()
window.run()
As you can see:
A Channel() object is created, named shapes_channel
A new window is created, with the shapes_channel passed into the constructor via the intermediate function new_window.
This window is passed to the other thread so that the other thread
can emit the relevant signal ("update_signal")
The other thread is run
The window is run in the main thread I get the following console output:
UPDATE SIGNAL CALLED
Num new shapes: 31
Gdk-Message: 01:27:14.090: main.py: Fatal IO error 0 (Success) on X server :0.
From the console output, we can infer that the signal is called successfully, and the new shapes are passed to the window and stored correctly, but it fails on the line self.show_all().
This is an object that was working fine previously, and producing graphical output, and I can only think of 2 possible things that may have changed from the objects perspective:
The Channel object works as intended, but perhaps the mere presence of an object that is shared across threads throws the whole thing into disarray
Even though it's on the main thread, it doesn't like that there are other threads.
I would really appreciate some guidance on this maddening occurrence.
About your assumptions:
It is unclear if your channel object is possible to safely access from two threads.
The signal handler is executed in the thread that emits the signal.
My guess would be that it is the fact that you emit the signal from another thread that causes the issue.
You can solve this by using GLib.idle_add(your_update_func). Instead of calling your_update_func directly, a request is added to the Gtk main loop, which executes it when there are no more events to process, preventing any threading issues.
Read more here: https://wiki.gnome.org/Projects/PyGObject/Threading
I am trying to use the following script to print documents. The problem is that
nothing happens. The word "execute" is printed and when I click on the dialog
CANCEL button the response is as expected. The PREVIEW and PRINT buttons cause
the dialog to exit but no result is printed. The three callback methods are
stubbed out with each printing its name, none of which are displayed.
I am using Ubuntu 18.04 with python 3.6.7.
import gi
gi.require_version ('Gtk', '3.0')
from gi.repository import Gtk, GLib, Gdk
def PrintManager (self):
ps = Gtk.PrintSettings.new ()
po = Gtk.PrintOperation.new ()
po.set_print_settings (ps)
po.set_n_pages (1)
po.connect ("begin_print", self.BeginPrint, self.PrintList)
po.connect ("draw_page", self.DrawPage, self.PrintList)
po.connect ("end_print", self.EndPrint, self.PrintList)
print ("execute") #x
result = po.run (Gtk.PrintOperationAction.PRINT_DIALOG, const.internal["parent"])
print (result) #x
if result == Gtk.PrintOperationResult.APPLY:
ps = op.get_print_settings ()
elif result == Gtk.PrintOperationResult.ERROR:
dialog = Gtk.MessageDialog.new (Gtk.DialogFlags.DESTROY_WITH_PARENT,
Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, const.printError)
dialog.run ()
dialog.destroy ()
def BeginPrint (self, po, ctx, data):
print ("{}.BeginPrint ()".format (__name__))
def DrawPage (self, po, ctx, cnt, data):
print ("{}.DrawPage ({})".format (__name__, cnt))
def EndPrint (self, po, ctx, data):
print ("{}.EndPrint ()".format (__name__))
There is something wrong with your program(most likely that const thing), because this does work as expected:
#!/usr/bin/env python
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class GUI:
def __init__(self):
self.window = Gtk.Window()
button = Gtk.Button(label = "print op")
button.connect("clicked", self.button_clicked )
self.window.add(button)
self.window.set_size_request(400, 400)
self.window.show_all()
def button_clicked (self, button):
ps = Gtk.PrintSettings.new ()
po = Gtk.PrintOperation.new ()
po.set_print_settings (ps)
po.set_n_pages (1)
self.PrintList = []
po.connect ("begin_print", self.BeginPrint, self.PrintList)
po.connect ("draw_page", self.DrawPage, self.PrintList)
po.connect ("end_print", self.EndPrint, self.PrintList)
print ("execute") #x
result = po.run (Gtk.PrintOperationAction.PRINT_DIALOG, self.window)
print (result) #x
if result == Gtk.PrintOperationResult.APPLY:
ps = po.get_print_settings ()
elif result == Gtk.PrintOperationResult.ERROR:
dialog = Gtk.MessageDialog.new (Gtk.DialogFlags.DESTROY_WITH_PARENT,
Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, po.printError)
dialog.run ()
dialog.destroy ()
def BeginPrint (self, po, ctx, data):
print ("{}.BeginPrint ()".format (__name__))
def DrawPage (self, po, ctx, cnt, data):
print ("{}.DrawPage ({})".format (__name__, cnt))
def EndPrint (self, po, ctx, data):
print ("{}.EndPrint ()".format (__name__))
def on_window_destroy(self, window):
Gtk.main_quit()
app = GUI()
Gtk.main()
I have a list of items in a QTreeView. Each item holds a QImage object. If I try to drag and drop the item, the program freezes. But when I comment out the line objMod._Image = QImage(flags = Qt.AutoColor), the program runs fine.
How can I drag and drop the items with the QImage object? The QImage holds an image which is rendered. The rendering process takes a while, so it would be nice to keep the QImage object.
import sys
import os
from PySide.QtCore import *
from PySide.QtGui import *
from PySide.QtUiTools import *
from PIL import Image, ImageCms, ImageQt
class ObjModel:
def __init__(self):
self._Image = None
class DragMoveTest(QMainWindow):
def __init__(self):
super(DragMoveTest,self).__init__()
self.initGUI()
self.show()
def initGUI(self):
self.treeView = QTreeView()
modelTreeView = QStandardItemModel()
self.treeView.setModel(modelTreeView)
for i in range(0, 4):
objMod = ObjModel()
objMod._Image = None
objMod._Image = QImage(flags = Qt.AutoColor)
item = QStandardItem('Test: %s' % str(i))
item.setData(objMod, Qt.UserRole + 1)
modelTreeView.invisibleRootItem().appendRow(item)
self.treeView.setDragDropMode(QAbstractItemView.InternalMove)
self.setCentralWidget(self.treeView)
def main(args):
app = QApplication(sys.argv)
qt_main_wnd = DragMoveTest()
ret = app.exec_()
sys.exit(ret)
if __name__ == "__main__":
main(sys.argv)
This is caused by a bug in PySide. During a drag and drop operation, the data in the dragged item must be serialized. This will be handled by Qt for most data-types, but for types that are specific to Python, special handling is required. This special handling seems to be broken in PySide. If your example is converted to PyQt, a TypeError is raised when trying to drag items, but the program does not freeze.
The source of the problem is that you are storing data using a custom Python class. PyQt uses pickle to serialize custom data-types, but it is not possible to also pickle the QImage that is stored in its __dict__, so the operation fails. I assume PySide must attempt something similar, but for some reason it does not raise an error when it fails. Qt grabs the mouse whilst dragging, so if the operation fails abnormally, it won't be released again, and the program will appear to freeze.
The simplest way to fix this is to avoid using a custom class to hold the QImage, and instead store the image directly in the item:
image = QImage()
item = QStandardItem('Test: %s' % i)
item.setData(image, Qt.UserRole + 1)
To store more data items, you can either use a different data-role for each one, or use a dict to hold them all:
data = {'image': QImage(), 'title': 'foo', 'timestamp': 1756790}
item.setData(data, Qt.UserRole + 1)
However, if you do this, you must always use string keys in the dict, otherwise you will face the same problems as before. (Using string keys means the dict can be converted into a QMap, which Qt knows how to serialize).
(NB: if you want to know whether a Qt class can be serialized, check the docs to see whether it defines the datastream operators).
I come up with a different solution. It is easier to have a object that holds a io.BytesIO. Your store the ImageData into the bytesIO variable. Upon on your image library you can open the image from the bytesIO variable.
In the demo the class ObjModel can handle QImage and Image from Pillow/PIL. If you use the set methods the image object will be converted into a bytesIO.
In short here a working example:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import os
import io
from PySide.QtCore import *
from PySide.QtGui import *
from PySide.QtUiTools import *
from PIL import Image, ImageCms, ImageQt
########################################################################
class ObjModel:
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
self._ImageByteIO = None
#----------------------------------------------------------------------
def getObjByte(self):
""""""
return self._ImageByteIO
#----------------------------------------------------------------------
def getQImage(self):
""""""
try:
self._ImageByteIO.seek(0)
qImg = QImage.fromData(self._ImageByteIO.getvalue())
return qImg
except:
return None
#----------------------------------------------------------------------
def getPILImage(self):
""""""
try:
self._ImageByteIO.seek(0)
img = Image.open(tBytesIO)
return img
except:
return None
#----------------------------------------------------------------------
def setObjByte(self, fileName):
""""""
try:
tBytesIO = io.BytesIO()
f = open (fileName, 'rb')
tBytesIO.write(f.read())
f.close()
self._ImageByteIO = tBytesIO
except:
self._ImageByteIO = None
#----------------------------------------------------------------------
def setQImage(self, qImg):
""""""
try:
tBytesIO = io.BytesIO()
qByteArray = QByteArray()
qBuf = QBuffer(qByteArray)
qBuf.open(QIODevice.ReadWrite)
qImg.save(qBuf, 'PNG')
tBytesIO = io.BytesIO()
tBytesIO.write(qByteArray.data())
self._ImageByteIO = tBytesIO
except:
self._ImageByteIO = None
#----------------------------------------------------------------------
def setPILImage(self, pImg):
""""""
tBytesIO = io.BytesIO()
pImg.save(tBytesIO, 'png')
self._ImageByteIO = tBytesIO
#----------------------------------------------------------------------
class DragMoveTest(QMainWindow):
def __init__(self):
""""""
super(DragMoveTest,self).__init__()
self.initGUI()
self.show()
#----------------------------------------------------------------------
def initGUI(self):
""""""
self.treeView = QTreeView()
modelTreeView = QStandardItemModel()
self.treeView.setModel(modelTreeView)
for i in range(0, 4):
objMod = ObjModel()
objMod.setQImage(QImage(flags = Qt.AutoColor))
item = QStandardItem('Test: %s' % str(i))
item.setData(objMod, Qt.UserRole + 1)
modelTreeView.invisibleRootItem().appendRow(item)
self.treeView.setDragDropMode(QAbstractItemView.InternalMove)
self.setCentralWidget(self.treeView)
#----------------------------------------------------------------------
def main(args):
app = QApplication(sys.argv)
qt_main_wnd = DragMoveTest()
ret = app.exec_()
sys.exit(ret)
#----------------------------------------------------------------------
if __name__ == "__main__":
main(sys.argv)
I've just been trying to practice some code by making a simple dice game
and using tkinter for the user interface of the starting menu for the game
For the starting menu, I'm trying to just see how it will come out if I used the code below,
BUT before making the Button widget and the Label Widgets, the commands come up first.
How would I fix this up?
thanks in advance
import tkinter as tk
from main import main
from written import showInstructions, showCredits
from generate_no import generate_no
class DiceGameUI(tk.Frame):
def __init__(self, master = None):
tk.Frame.__init__(self, master)
self.grid()
self.createWidgets()
def createWidgets(self):
self.titleLabel = tk.Label(self, fg = "red") #The Title of the Game
self.titleLabel["text"] = "Dice Game"
self.startButton = tk.Button(self) #Start Button
self.startButton["text"] = "Roll On!"
self.startButton["command"] = main() <<----- This plays out first before
self.startButton.grid() making any widgets
self.instrButton = tk.Button(self) #Instructions Button
self.instrButton["text"] = "Instructions"
self.instrButton["command"] = showInstructions()
self.instrButton.grid()
self.credits = tk.Button(self) #Credits Button
self.credits["text"] = "Credits"
self.credits["command"] = showCredits()
self.credits.grid()
root = tk.Tk() #Run code using tkinter
app = DiceGameUI(master = root)
app.mainloop()
'
You have to assign only name of function without () and arguments
self.startButton["command"] = main
If you use () than you run that function and result is assigned to command. It is good to create dynamicly function for command.
If you will need assign function which require arguments you have to use lambda function.
self.startButton["command"] = lambda:main()
self.startButton["command"] = lambda:main("abc", 123)
a = "abc"
b = 123
self.startButton["command"] = lambda arg1=a,arg2=b:main(arg1,arg2)
self.startButton["command"] = lambda title=a,count=b:main(title,count)
# this may not work - especially if a or b changes value (for example in loop)
self.startButton["command"] = lambda:main(a, b)
example how to use function name in own code
def plus(a, b):
return a + b
def minus(a, b):
return a - b
def result(a, b, func_name):
return func_name(a,b)
print result(10, 7, plus) # 17
print result(10, 7, minus) # 3
I'm having trouble implementing a thread correctly to keep my application from locking up and experiencing weird behavior. The app is designed to log into a ubuntu based server or ubuntu embedded server and search for log files that may be in the clear. The embedded server works, but the app keeps locking up while the search is occurring. The siteserver will not process. I have yet to code the local file search. I would like to add a progress bar once I figure out how to implement threads. I thought this would be straight forward since I've been learning and working with Python for several months now, but working with a GUI has its challenges. I'm still a neophyte and open to all the criticisms; it only helps me to become a better programmer. Any help is greatly appreciated. Here is the code below:
#!c:\python27
import wx
import os
import re
import paramiko
import string
import fileinput
import os.path
import dircache
import sys
import time
import datetime, time
import wx
from wxGui import *
class MyApp(wx.App):
def OnInit(self):
frame = MyFrame("SecureTool v2.0.0", (50, 60), (458, 332))
frame.Show()
self.SetTopWindow(frame)
return True
class MyFrame(wx.Frame):
def __init__(self, title, pos, size):
wx.Frame.__init__(self, None, -1, title, pos, size)
toolbar = self.CreateToolBar()
toolbar.Realize()
menuFile = wx.Menu()
menuFile.Append(1, "&About...")
menuFile.AppendSeparator()
menuFile.Append(2, "E&xit")
menuBar = wx.MenuBar()
menuBar.Append(menuFile, "&File")
menu2 = wx.Menu()
menu2.Append(wx.NewId(), "&Copy", "Copy in status bar")
menu2.AppendSeparator()
menu2.Append(wx.NewId(), "C&ut", "")
menu2.AppendSeparator()
menu2.Append(wx.NewId(), "Paste", "")
menu2.AppendSeparator()
menu2.Append(wx.NewId(), "&Options...", "Display Options")
menuBar.Append(menu2, "&Edit")
self.SetMenuBar(menuBar)
self.CreateStatusBar()
self.SetStatusText("Welcome to SecureTool!")
self.Bind(wx.EVT_MENU, self.OnAbout, id=1)
self.Bind(wx.EVT_MENU, self.OnQuit, id=2)
panel = wx.Panel(self)
panel.SetBackgroundColour('LIGHT GREY')
#Close button
button = wx.Button(panel, label="EXIT", pos=(229, 160), size=(229, 80))
self.Bind(wx.EVT_BUTTON, self.OnQuit, button)
self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
#Embed Server button
button2 = wx.Button(panel, label="Embed Server", pos=(0, 160), size=(229, 80))
self.Bind(wx.EVT_BUTTON, self.OnIP, button2)
#Site Server
button3 = wx.Button(panel, label="SITESERVER", pos=(0, 80), size=(229, 80))
self.Bind(wx.EVT_BUTTON, self.OnUsrPswd, button3)
#Local Search
button4 = wx.Button(panel, label="LOCAL SEARCH", pos=(229, 80), size=(229, 80))
self.Bind(wx.EVT_BUTTON, self.OnOpen, button4)
EVT_RESULT(self, self.OnResult)
self.worker = None
def OnIP(self, event):
ip_address = 0
result = ''
dlg = wx.TextEntryDialog(None, "Enter the IP Address.",
'Embed Server Connect', 'xxx.xxx.xxx.xxx')
if dlg.ShowModal() == wx.ID_OK:
ip_address = dlg.GetValue()
if ip_address:
cmsg = wx.MessageDialog(None, 'Do you want to connect to: ' + ip_address,
'Connect', wx.YES_NO | wx.ICON_QUESTION)
result = cmsg.ShowModal()
if result == wx.ID_YES:
self.DispConnect(ip_address)
cmsg.Destroy()
dlg.Destroy()
return True
def OnUsrPswd(self, event):
passwrd = 0
result = ''
result = wx.TextEntryDialog(None, 'Enter Weekly Password', 'Site Server login','')
if result.ShowModal() == wx.ID_OK:
passwrd = result.GetValue()
if passwrd:
psmsg = wx.MessageDialog(None, 'Do you want to connect to the Siteserver?', 'Connect',
wx.YES_NO | wx.ICON_QUESTION)
result = psmsg.ShowModal()
if result == wx.ID_YES:
self.SiteserverConnect(passwrd)
psmsg.Destroy()
result.Destroy()
return True
def ErrMsg(self):
ermsg = wx.MessageDialog(None, 'Invalid Entry!', 'ConnectionDialog', wx.ICON_ERROR)
ermsg.ShowModal()
ermsg.Destroy()
def GoodConnect(self):
gdcnt = wx.MessageDialog(None, 'You are connected!', 'ConnectionStatus', wx.ICON_INFORMATION)
gdcnt.ShowModal()
#if gdcnt.ShowModal() == wx.ID_OK:
gdcnt.Destroy()
def OnFinish(self):
finish = wx.MessageDialog(None, 'Job is finished!', 'WorkStatus', wx.ICON_INFORMATION)
finish.ShowModal()
finish.Destroy()
def DispConnect(self, address):
pattern = r"\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b"
port = 22
user = 'root'
password ='******'
if re.match(pattern, address):
ssh = paramiko.SSHClient()
ssh.load_system_host_keys()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(address,port,user,password)
Ssh = ssh
self.GoodConnect()
self.OnSearch(Ssh)
else:
self.ErrMsg()
def SiteserverConnect(self, password):
port = 22
user = 'root2'
address = '10.5.48.2'
if password:
ssh = paramiko.SSHClient()
ssh.load_system_host_keys()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(address,port,user,password)
Ssh = ssh
self.GoodConnect()
self.OnSiteSearch(Ssh)
else:
self.ErrMsg()
def startWorker(self,a, b, c):
self.button2.Disable()
self.thread = Thread(target=self.LongRunningSearch)
self.thread.start()
def OnSearch(self, sssh):
self.startWorker(self.OnFinish, self.LongRunningSearch, wargs=[sssh])
self.OnFinish()
def LongRunningSearch(sssh):
ssh = sssh
apath = '/'
apattern = '"*.txt" -o -name "*.log"'
rawcommand = 'find {path} -name "*.txt" -o -name "*.log"'
command1 = rawcommand.format(path=apath, pattern=apattern)
stdin, stdout, stderr = ssh.exec_command(command1)
filelist = stdout.read().splitlines()
ftp = ssh.open_sftp()
for afile in filelist:
(head, filename) = os.path.split(afile)
paths = '/dispenser_result.log'
temp = ftp.file(paths, 'w')
from time import strftime
temp.write("{0:^75}".format("Company -Security Report" ) + strftime(" %Y-%m-%d %H:%M:%S") + "\n\n")
ustring = wx.TextEntryDialog(None, 'Enter a search string below:', 'Search', 'String Name')
if ustring.ShowModal() == wx.ID_OK:
userstring = ustring.GetValue()
if userstring:
userStrHEX = userstring.encode('hex')
userStrASCII = ''.join(str(ord(char)) for char in userstring)
regex = re.compile(r"(%s|%s|%s)" % ( re.escape( userstring ), re.escape( userStrHEX ), re.escape( userStrASCII )))
else:
sys.exit('You Must Enter A String!!!')
count = 0
for afile in filelist:
(head, filename) = os.path.split(afile)
if afile.endswith(".log") or afile.endswith(".txt"):
f=ftp.open(afile, 'r')
for i, line in enumerate(f.readlines()):
result = regex.search(line)
if result:
count += 1
ln = str(i)
pathname = os.path.join(afile)
template = "\n\nLine: {0}\nFile: {1}\nString Type: {2}\n\n"
output = template.format(ln, pathname, result.group())
ftp.get(afile, 'c:\\Extracted\\' + filename)
temp.write(output)
break
else:
#print "No Match in: " + os.path.join(afile)
temp.write("\nNo Match in: " + os.path.join(afile))
f.close()
for fnum in filelist:
#print "\nFiles Searched: ", len(filelist)
#print "Files Matched: ", count
num = len(filelist)
temp.write("\n\nFiles Searched:" + '%s\n' % (num))
temp.write("Files Matched:"+ '%s\n' % (count))
temp.write("Search String:"+ '%s\n' % (userstring))
break
temp.close()
defaultFolder = "DispenserLogResults"
if not defaultFolder.endswith(':') and not os.path.exists('c:\\Extracted\\DispenserLogResults'):
os.mkdir('c:\\Extracted\\DispenserLogResults')
else:
pass
ftp.get(paths, 'c:\\Extracted\\DispenserLogResults\\dispenser_result.log')
ftp.remove(paths)
re.purge()
ftp.close()
ssh.close()
def OnSiteSearch(self, sssh):
ssh = sssh
apath = '/var/log/apache2 /var/opt/smartmerch/log/'
apattern = '"*.log"'
rawcommand = 'find {path} -type f -name "*.log"'
command1 = rawcommand.format(path=apath, pattern=apattern)
stdin, stdout, stderr = ssh.exec_command(command1)
filelist = stdout.read().splitlines()
ftp = ssh.open_sftp()
for afile in filelist:
(head, filename) = os.path.split(afile)
paths = '/var/tmp/siteserver_result.log'
temp = ftp.file(paths, 'w')
from time import strftime
temp.write("{0:^75}".format("Gilbarco - SQA Security Report" ) + strftime(" %Y-%m-%d %H:%M:%S") + "\n\n")
temp.write("\n{0:^75}".format("SiteServer Logs" ))
ustring = wx.TextEntryDialog(None, 'Enter a search string below:', 'Search', 'String Name')
if ustring.ShowModal() == wx.ID_OK:
userstring = ustring.GetValue()
if userstring:
userStrHEX = userstring.encode('hex')
userStrASCII = ''.join(str(ord(char)) for char in userstring)
regex = re.compile(r"(%s|%s|%s)" % ( re.escape( userstring ), re.escape( userStrHEX ), re.escape( userStrASCII )))
else:
sys.exit('You Must Enter A String!!!')
count = 0
for afile in filelist:
(head, filename) = os.path.split(afile)
if afile.endswith(".log") or afile.endswith(".txt"):
f=ftp.open(afile, 'r')
for i, line in enumerate(f.readlines()):
result = regex.search(line)
if result:
count += 1
ln = str(i)
pathname = os.path.join(afile)
template = "\n\nLine: {0}\nFile: {1}\nString Type: {2}\n\n"
output = template.format(ln, pathname, result.group())
ftp.get(afile, 'c:\\Extracted\\' + filename)
temp.write(output)
break
else:
temp.write("\nNo Match in: " + os.path.join(afile))
f.close()
for fnum in filelist:
num = len(filelist)
temp.write("\n\nFiles Searched:" + '%s\n' % (num))
temp.write("Files Matched:"+ '%s\n' % (count))
temp.write("Search String:"+ '%s\n' % (userstring))
break
temp.close()
defaultFolder = "SiteServerLogResults"
if not defaultFolder.endswith(':') and not os.path.exists('c:\\Extracted\\SiteServerLogResults'):
os.mkdir('c:\\Extracted\\SiteServerLogResults')
else:
pass
ftp.get(paths, 'c:\\Extracted\\SiteServerLogResults\\siteserver_result.log')
ftp.remove(paths)
re.purge()
ftp.close()
ssh.close()
self.OnFinish()
def OnOpen(self,e):
self.dirname = ''
dlg = wx.FileDialog(self, "Choose a file", self.dirname, "", "*.*", wx.OPEN)
if dlg.ShowModal() == wx.ID_OK:
self.filename = dlg.GetFilename()
self.dirname = dlg.GetDirectory()
f = open(os.path.join(self.dirname, self.filename), 'r')
self.control.SetValue(f.read())
f.close()
dlg.Destroy()
def OnQuit(self, event):
self.Close(True)
def OnAbout(self, event):
wx.MessageBox("This is sQAST v2.0.0",
"About secureTool", wx.OK | wx.ICON_INFORMATION, self)
def OnCloseWindow(self, event):
self.Destroy()
if __name__ == '__main__':
app = MyApp(False)
app.MainLoop()
Traceback Error after running:
Traceback (most recent call last):
File "C:\SQA_log\wxGui.py", line 87, in OnIP
self.DispConnect(ip_address)
File "C:\SQA_log\wxGui.py", line 143, in DispConnect
self.OnSearch(Ssh)
File "C:\SQA_log\wxGui.py", line 169, in OnSearch
self.startWorker(self.OnFinish, self.LongRunningSearch, wargs=[sssh])
In your particular case I would do something like:
1) Encapsulate the long task and separate it from the GUI reaction, simplify your method:
def OnSearch(self, sssh):
self.LongRunningSearch(sssh) # Move all the blocking code here,
# just NOT the GUI reaction !
# Meaning self.OnFinish()...
self.OnFinish()
2) Verify that it still runs fine. Then modify the method to add the thread:
def OnSearch(self, sssh):
startWorker(self.OnFinish, self.LongRunningSearch, wargs=[sssh])
self.OnSearch will end immediately and self.OnFinish will be called after the thread running self.LongRunningSearch has finished. It may still need some tuning as I am unable to run your code on my computer.
I don't see any threading in your application at all. Whenever you make a call to something that will take a while, that something needs to run in a separate thread or it will block the main loop of your GUI.
You should read the following wiki entry on threading in wxPython: http://wiki.wxpython.org/LongRunningTasks
I have used the information therein to successfully create threaded wxPython applications. There's also a simple threading tutorial here: http://www.blog.pythonlibrary.org/2010/05/22/wxpython-and-threads/
Hope that helps. If you get stuck, you should post to the official wxPython mailing group: https://groups.google.com/forum/#!forum/wxpython-users Those guys will set you straight.
You can also have a look at convenience module for threading implemented in the wx, wx.lib.delayedresult. It is very easy to use and to add when you find it is needed. I am not sure why it is ignored so often. I have written an example which uses it some time ago here.
It basically needs you to create two functions / methods. First, which will be ran in another thread, and second, which will be ran after another thread finishes. Then you just call startWorker(LongTaskDone, LongTask).
Example 1: Using wx.lib.delayedresult. wx.CallAfter is used to show progress in GUI thread using gauge widget. Official Documentation.
from time import sleep
import wx
from wx.lib.delayedresult import startWorker
class MainWindow(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
self.panel = wx.Panel(self)
self.startButton = wx.Button(self.panel, label="Long Task")
self.abortButton = wx.Button(self.panel, label="Abort")
self.abortButton.Disable()
self.gauge = wx.Gauge(self.panel, size=(-1, 20))
self.shouldAbort = False
self.startButton.Bind(wx.EVT_BUTTON, self.OnStartButton)
self.abortButton.Bind(wx.EVT_BUTTON, self.OnAbortButton)
self.windowSizer = wx.BoxSizer()
self.windowSizer.Add(self.panel, 1, wx.ALL | wx.EXPAND)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.startButton)
self.sizer.Add(self.abortButton)
self.sizer.Add((10, 10))
self.sizer.Add(self.gauge)
self.border = wx.BoxSizer()
self.border.Add(self.sizer, 1, wx.ALL | wx.EXPAND, 5)
self.panel.SetSizerAndFit(self.border)
self.SetSizerAndFit(self.windowSizer)
self.Show()
def OnStartButton(self, e):
self.startButton.Disable()
self.abortButton.Enable()
startWorker(self.LongTaskDone, self.LongTask)
def OnAbortButton(self, e):
self.shouldAbort = True
def LongTask(self):
for a in range(101):
sleep(0.05)
wx.CallAfter(self.gauge.SetValue, a)
if self.shouldAbort:
break
return self.shouldAbort
def LongTaskDone(self, result):
r = result.get()
if r:
print("Aborted!")
else:
print("Ended!")
self.startButton.Enable()
self.abortButton.Disable()
self.shouldAbort = False
self.gauge.SetValue(0)
app = wx.App(False)
win = MainWindow(None)
app.MainLoop()
Example 2: Using standard threading module. In some cases this may be more "ugly". I would recommend using wx.lib.delayedresult. Official Documentation.
from time import sleep
from threading import Thread
import wx
class MainWindow(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
self.panel = wx.Panel(self)
self.startButton = wx.Button(self.panel, label="Long Task")
self.abortButton = wx.Button(self.panel, label="Abort")
self.abortButton.Disable()
self.gauge = wx.Gauge(self.panel, size=(-1, 20))
self.shouldAbort = False
self.thread = None
self.startButton.Bind(wx.EVT_BUTTON, self.OnStartButton)
self.abortButton.Bind(wx.EVT_BUTTON, self.OnAbortButton)
self.windowSizer = wx.BoxSizer()
self.windowSizer.Add(self.panel, 1, wx.ALL | wx.EXPAND)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.startButton)
self.sizer.Add(self.abortButton)
self.sizer.Add((10, 10))
self.sizer.Add(self.gauge)
self.border = wx.BoxSizer()
self.border.Add(self.sizer, 1, wx.ALL | wx.EXPAND, 5)
self.panel.SetSizerAndFit(self.border)
self.SetSizerAndFit(self.windowSizer)
self.Show()
def OnStartButton(self, e):
self.startButton.Disable()
self.abortButton.Enable()
self.thread = Thread(target=self.LongTask)
self.thread.start()
def OnAbortButton(self, e):
self.shouldAbort = True
def LongTask(self):
for a in range(101):
sleep(0.05)
wx.CallAfter(self.gauge.SetValue, a)
if self.shouldAbort:
break
wx.CallAfter(self.LongTaskDone, self.shouldAbort)
def LongTaskDone(self, r):
if r:
print("Aborted!")
else:
print("Ended!")
self.startButton.Enable()
self.abortButton.Disable()
self.shouldAbort = False
self.gauge.SetValue(0)
app = wx.App(False)
win = MainWindow(None)
app.MainLoop()
Note: threading.Lock may be needed for thread-safe passing of more complicated variables and data than simple boolean flag.
Edit: Added examples.
Edit: Added ability to abort the thread.
Edit: Simplified the examples. Got rid of timer based on tom10's idea and also deleted threading.Lock as it is not needed here.
In wxPython, all calls to methods of GUI objects and event handlers need to happen in the main thread. Because of this, you need to be careful when using threading with wx, but it's usually easy to make the required modifications.
In your code, for example, you could do the call to wx.TextEntryDialog from the main thread, and then pass this information to the search thread.
If you need to request action of the GUI from the thread, the easiest way is to use wx.CallAfter, though there are other approaches that work as well.