I have the following file upload code. I want to modify this code for two things:
1.If the user cancels the askopenfilenames command, the overall entire program will stop.
2.If the user does not select the required number of files, the function fileupload will restart, until the correct number of files is selected.
import Tkinter
from Tkinter import Tk
tk=Tk()
from tkFileDialog import askopenfilenames
import tkMessageBox
def fileupload():
tk.withdraw()
uploadedfiles = askopenfilenames(multiple=True)
##if user cancels: (IF STATEMENT TO RESULT IN MESSAGEBOX AND CODE TO STOP)
###tk.withdraw()
###tkMessageBox.showinfo(message="File Upload has been cancelled program will stop")
##Stop code
if len(uploadedfiles)>2 or len(uploadedfiles)<2:
tk.withdraw()
tkMessageBox.showinfo(message="2 files have not been selected!")
##rerun function to reselect files
return uploadedfiles
uploadedfiles=fileupload()
print uploadedfiles
First check if the string returned by askopenfilenames is empty, which means that the user closed the dialog. Then use tk.splitlist to create a list from the string (if it is not empty) and check its length:
tk=Tk()
tk.withdraw()
def fileupload():
while True:
uploadedfilenames = askopenfilenames(multiple=True)
if uploadedfilenames == '':
tkMessageBox.showinfo(message="File Upload has been cancelled program will stop")
return
uploadedfiles = tk.splitlist(uploadedfilenames)
if len(uploadedfiles)!=2:
tkMessageBox.showinfo(message="2 files have not been selected!")
else:
return uploadedfiles
print fileupload()
Related
I made an App to process and display some data in a Tkinter window. I now want to send the contents of the window to a printer for printing on actual paper. However I don't really see any libraries in tkinter or Python to do this. I have to confess I am very new to tkinter and Python.....
Can anyone point me in the right direction?
Thanks.
tkinter is for a graphics user interface and so is all about display. To print data in a tkinter widget you'd have to retrieve that data depending on what the widget is and put it on the clipboard (can do this in tkinter) or file it (in a separate function) and use a separate printing app to print.
(edited as per comment)
This code does much the same as the subprocess module in a minimalist fashion since you have a specific task on Windows. To test it needs a pdf filepath inserted so I've put in an example that brings up notepad just so it can run as it is.
This has an alternative to checking for print status by use of a manual pause. Then Adobe (or any executable that has the appropriate print facility) can be closed automatically. I'd expect the manual pause to be replaced by an automatic timer set for an estimate time for a document to print. Probably need to consider only the time needed to transfer the document into the printing buffer - but that is up to how you want to operate with your system.
"""Process to start external executable.
. default is to let process run until parent pause is complete then process is terminated in parent,
.. this allows time for a process started im the child like printing to finish.
. option to wait until process has finished before returning to parent.
(proc.py)
"""
import _winapi as win
from os import waitpid
from sys import exc_info as ei
def startproc(exe,cmd, wait=False):
try:
ph, th, pid, tid = win.CreateProcess(exe,cmd,None,None,1,0,None,None,None)
win.CloseHandle(th)
except:
print(ei()[1])
ph = 0
return (ph,'error')
if ph > 0:
if not wait:
return (ph,'process still going')
else:
pid, exitstatus = waitpid(ph,0)
return (0,'process done')
#exe = "C:\\Program Files\\Adobe\\Acrobat DC\\Acrobat\\Acrobat.exe"
#cmd = "open <pdf filepath>"
exe = "C:\Windows\System32\\notepad.exe"
cmd = None
print(__doc__)
proc,msg = startproc(exe,cmd)
print(msg)
if 'done' not in msg: # manual pause for printing
input('\n-- carry on --\n') # could be automatic timer
if msg != 'error' and proc != 0:
if win.GetExitCodeProcess(proc) == win.STILL_ACTIVE:
win.TerminateProcess(proc,0)
if 'done' not in msg: print('process closed')
#can delete pdf here
input('\n--- finish ---\n')
I am working with some proprietary business software written in DB/C, a short-lived variant of COBOL over 20 years ago with no access to source code or useful documentation of any kind. I've been trying to automate some of our processes with python, and have written a handler object that can pass commands and send various key codes using pyautogui but I have reached a barrier where sometimes I need to rely on the output of the previous routine to decide when/whether to trigger the next. The software GUI runs in a console window, similar to ncurses.
How can I copy the entire contents of my console window to my clipboard? If there is a way to copy it directly to a local python variable that would be ideal; Once I have the screen text I can just match the part I need with a regex.
Here is my handler so far just to give you an idea:
import pyautogui
import time
import subprocess
class ECISession:
def __init__(self, username, password):
self.username = username
self.password = password
self.openECI()
self.login(username, password)
def openECI(self):
# Open ECI as a subprocess
subprocess.Popen("F:\\ECI\\hp4\\test\\s.bat")
def login(self, username, password):
# Login to ECI Session with username and password
time.sleep(15)
pyautogui.write(username, interval=0.1)
pyautogui.press('enter')
pyautogui.write(password, interval=0.1)
pyautogui.press('enter')
pyautogui.write('Y') # Make sure it ignores duplicate login
#staticmethod
def send(text='', supressEnter=False):
# Send passed text to console and press enter unless specified to supress
if text != '':
pyautogui.write(text, interval=0.1)
if supressEnter:
pass
else:
pyautogui.press('enter')
time.sleep(1)
#staticmethod
def sendF3(n=1):
# Send F3 save key 1 time by default, n times if needed
while n != 0:
pyautogui.press('F3')
n -= 1
#staticmethod
def sendF4(n=1):
# Send F4 search key 1 time by default, n times if needed
while n != 0:
pyautogui.press('F4')
n -= 1
#staticmethod
def readscreen():
# return entire console window text
pass
The readscreen() method is what I need to figure out. I just want to return the console content. I would just use the mouse to highlight the entire thing and press enter, but I have no way to make sure the window starts in the same place every time; It can't be maximized or it will crash since it expects an 80 column display with a specific font size.
FYI, the software in question is HealthPac by Eldorado Computing Incorporated. If any of you have used it you know the struggle. I would post some screenshots but it may be a HIPPA violation or something.
i have a python class that create a window that includes
EditLine
open button
cancel button
where the EditLine will get the userInput that is a path for folder.
the problem is that once i run the script it enter in infinite loop.
code:
'''
1- import the libraries from the converted file
2- import the converted file
'''
from PyQt5 import QtCore, QtGui, QtWidgets
import pathmsgbox
import os
import pathlib
class path_window(pathmsgbox.Ui_PathMSGbox):
def __init__(self,windowObject ):
self.windowObject = windowObject
self.setupUi(windowObject)
self.checkPath(self.pathEditLine.text())
self.windowObject.show()
def checkPath(self, pathOfFile):
folder = self.pathEditLine.text()
while os.path.exists(folder) != True:
print("the specified path not exist")
folder = self.pathEditLine.text()
return folder
'''
get the userInput from the EditLine
'''
'''
def getText(self):
inputUser = self.pathEditLine.text()
print(inputUser)
'''
'''
function that exit from the system after clicking "cancel"
'''
def exit():
sys.exit()
'''
define the methods to run only if this is the main module deing run
the name take __main__ string only if its the main running script and not imported
nor being a child process
'''
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
PathMSGbox = QtWidgets.QWidget()
pathUi = path_window(PathMSGbox)
pathUi.pathCancelBtn.clicked.connect(exit)
sys.exit(app.exec_())
The problem here is that you're calling checkPath() in the class initialization.
checkPath() read the path one time, and then start to evaluate if that path is valid 'forever'. This while loop running may even prevent the software to be able to effectively read again the text from self.pathEditLine.
Usually it's better to connect each function to an event:
Check if the folder exist when a button is pressed
Check if the folder exist when the text change
Check if the folder exist when the user press enter
For doing any of these, you have to connect one of these events to the function:
button event:
self.btnMyNewButton.clicked.connect(checkPath)
text changing event:
self.pathEditLine.textChanged.connect(checkPath)
enter button event:
self.pathEditLine.returnPressed.connect(checkPath)
This means that you have to substitute one of the previous lines with the line where you call the checkPath() function in the initialization:
def __init__(self,windowObject ):
self.windowObject = windowObject
self.setupUi(windowObject)
self.pathEditLine.textChanged.connect(checkPath)
self.windowObject.show()
you also have to remove the pathOfFile argument from checkPath(self, checkPath) because you are not using it.
Since we decided a different behaviour for our checkPath() function, we no longer need a while loop: we will be reading the user input each time the event occurs, evaluate the user input, return the user input if we like it or return False if we don't:
def checkPath(self):
folder = str(self.pathEditLine.text())
if os.path.exists(folder):
print '%s is a valid folder' % folder
return folder
else:
print '%s is NOT a valid folder' % folder
return False
I currently have a main python script (main.py) which reads input from a second script (input.py) which can be modified by a user. The user sets variables such as number of dimensions (ndim), number of points (npts) etc. in the second script and these are read into main.py using the following:
filename = sys.argv[-1]
m = __import__(filename)
ndim = m.ndim
npts1 = m.npts1
npts2_recorded = m.npts2_recorded
The script is executed by the following command:
python main.py input
I would like to replace input.py with a GUI. Tkinter seems a sensible place to start and I can see how to create a GUI to enable the user to set the various options that they would otherwise have set in input.py. However, I do not know how to pass this information to main.py from the GUI. Is there an equivalent to __import(filename)__ which can extract information from selections made by a user in the GUI, or is there another way of achieving the same effect.
A minimal (not) working example based on the answer below:
This code creates the file example.txt but the text given to block1 does not get written to the file.
from Tkinter import *
def saveCallback():
with open("example.txt",'w') as outfile:
outfile.write(block1.get())
def UserInput(status,name):
optionFrame = Frame(root)
optionLabel = Label(optionFrame)
optionLabel["text"] = name
optionLabel.pack(side=LEFT)
var = StringVar(root)
var.set(status)
w = Entry(optionFrame, textvariable= var)
w.pack(side = LEFT)
optionFrame.pack()
return w
if __name__ == '__main__':
root = Tk()
block1 = UserInput("", "Block size, dimension 1")
Save_input_button = Button(root, text = 'Save input options', command = saveCallback())
Save_input_button.pack()
root.mainloop()
Use a file for that, save selections in the GUI to a file(just like you did before with input.py) and then read the file.
So, in your main.py
Open the GUI
The preferences entered by to user to the file
Read the file as you did before.
The only drawback here is that you have to make sure in your main.py script that the GUI have been already closed. For that you can use the subprocess module, there are several function there you can use for block until the process returns or ends.
With this approach you just have to type:
python main.py
and somewhere inside main.py:
# The function call will wait for command to complete, then return the returncode attribute.
rcode = subprocess.call(['python', 'gui_input.py'])
Code sample to write the value of an Entry to a file.
import tkinter
top = tkinter.Tk()
def saveCallback():
with open("example.txt", 'w') as outfile:
outfile.write(e1.get())
e1 = tkinter.Entry(top)
b1 = tkinter.Button(top, text ="Save", command = saveCallback)
e1.pack(side=tkinter.LEFT)
b1.pack(side=tkinter.RIGHT)
top.mainloop()
I am building application with interactive console interface (line htop, atop utilities) using urwid library, so my trouble is: as interface takes all the space in console window - I could not see python's errors, I tried to do that:
import sys
f = open("test_err", "w")
original_stderr = sys.stderr
sys.stderr = f
print a #a is undefined
sys.stderr = original_stderr
f.close()
It works when I dont use urwid, but not when I use it...
you could try redirecting errors to a file. after each time you run the program, you will need to refresh the file. most editors let you easily do this by pushing f5
def main():
#your code here
print someError #raises an error
try: #run main function
main()
except BaseException as err: #catch all errors
with open('errors.txt','a') as errors: #open a file to write the errors to
errors.write(err.message+'\n')#write the error
change the 'a' to 'w' in the open function if you only want to see one error in the file at a time (instead of having multiple error over a long period of time in one file).
if you want to see the error right when it happens, you can make the error catcher open a window that has the error on it.
def main():
#your code here
print someErr
try: #run main function
main()
except BaseException as err: #catch all errors
import Tkinter as tk #imports the ui module
root = tk.Tk() #creates the root of the window
#creates the text and attaches it to the root
window = tk.Label(root, text=err.message)
window.pack()
#runs the window
root.mainloop()
if you want to build your own window to catch errors, you can learn about Tkinter here. (it is built into python, you don't have to install anything)
Here's what I came up with. I'm taking advantage of unicode-rxvt (urxvt) feature to be passed in a file descriptor. Of course this means you need to be developing this in an X environment, and not a console.
from __future__ import print_function
import os
from datetime import datetime
_debugfile = None
def _close_debug(fo):
fo.close()
def DEBUG(*obj):
"""Open a terminal emulator and write messages to it for debugging."""
global _debugfile
if _debugfile is None:
import atexit
masterfd, slavefd = os.openpty()
pid = os.fork()
if pid: # parent
os.close(masterfd)
_debugfile = os.fdopen(slavefd, "w+", 0)
atexit.register(_close_debug, _debugfile)
else: # child
os.close(slavefd)
os.execlp("urxvt", "urxvt", "-pty-fd", str(masterfd))
print(datetime.now(), ":", ", ".join(map(repr, obj)), file=_debugfile)
This will open a new terminal window automatically when you call DEBUG for the first time and close it at exit. Then any messages passed to it are shown in this new window. This is your "debug window". So your main app works normally, without cluttering it up with messages, but you can still see debug output in this new terminal.