I am trying to make an antivirus application but I met some issue. After I press the button Scan Now, the GUI become unclickable and Not Responding but the program still running in my IDE. I am thinking to limit the file read per second, is this possible? Or is there any others solution for this issue?
This is my coding:
def md5(self,fname):
hash_md5 = hashlib.md5()
try:
with open(fname, "rb") as f:
for chunk in iter(lambda: f.read(2 ** 20), b""):
hash_md5.update(chunk)
except Exception:
pass
return hash_md5.hexdigest()
def get_all_abs_paths(self,rootdir):
self.progressBar['value'] = self.progressBar['value'] + 5
viruslist = open('C:\FYP\SecuCOM2022\compile.txt','rt')
virusinside = [l.rstrip() for l in viruslist]
paths = list()
virus="detected"
novirus="clear"
for dirpath,_,filenames in os.walk(rootdir):
for f in filenames:
paths.append(os.path.abspath(os.path.join(dirpath, f)))
def getfile(self):
file2=('C:/Windows/System32')
file3=('C:/Program Files')
self.status.set("Scanning...")
self.progressBar['value'] = self.progressBar['value'] + 5
self.get_all_abs_paths(file3)
self.progressBar['value'] = self.progressBar['value'] + 45
self.get_all_abs_paths(file2)
self.status.set("Finished Scan")
self.progressBar['value'] = self.progressBar['value'] + 50
You need to create a thread to run the scan function, see https://pypi.org/project/pythread/
What happens right now is that the Tkinter gui and the scan function run in the same unique thread of your application, so when scan function is running the gui is not, which is why it freeze.
By creating a thread you will have both the gui and the scan function running at the same time in parallel.
Tkinter GUIs have a mainloop and calling any function will cause it to pause until the function is exited.
You can run the function on a seperate thread to allow the rest of the GUI to work while a task is being done.
GUI toolkits like tkinter are event-driven. To work properly, the
mainloop must continuously be able to process keyboard and mouse events.
When it is not processing events, it will start scheduled idle tasks.
So they work quite differently from normal Python scripts that just run from
top to bottom.
A tkinter program runs within the mainloop. So there are only three
things you do before starting the mainloop.
Create a window with some widgets on it.
Create objects (variables) that hold program state.
Define functions that can be run from the mainloop as callbacks or
idle tasks.
A callback is called in response to activating a control (like clicking on
a button).
An idle task is started by the system after a specified number of milliseconds
when the system is not busy processing events. You can schedule idle tasks
with the Tk.after() method.
Basically, the callbacks and idle tasks are your program.
To keep the GUI responsive, callbacks and idle tasks should not take too long; say 50 ms.
So running a complete antivirus scan in a single callback will indeed make the GUI unresponsive.
Basically, there are three possible solutions.
Chop up the scanning process in small pieces. The first piece is executed in a callback, the rest is done in idle tasks. This is probable the most simple solution, because it makes it easy to update the GUI when you're scannning.
Use multiprocessing to start a separate program to do the scanning. Set up a Pipe to enable communication between the GUI and scanning programs. Use an idle task in the GUI to read messages from the pipe and update the GUI accordingly.
Use threading to start a seperate thread to do the scanning. There is some confusion as to tkinter being actually safe to call from multiple threads; see the example below.
Which one works best for you hard for me to say.
Below I give examples for 1 and 3 in the form of a tkinter script to unlock ms-excel files.
First the none-threaded version:
"""Remove passwords from modern excel 2007+ files (xlsx, xlsm)."""
from types import SimpleNamespace
import os
import re
import shutil
import stat
import sys
import zipfile
from tkinter import filedialog
from tkinter import ttk
from tkinter.font import nametofont
import tkinter as tk
__version__ = "2020.04.20"
def create_widgets(root):
"""Create the window and its widgets.
Arguments:
root: the root window.
Returns:
A SimpleNamespace of widgets
"""
# Set the font.
default_font = nametofont("TkDefaultFont")
default_font.configure(size=12)
root.option_add("*Font", default_font)
# General commands and bindings
root.bind_all('q', do_exit)
root.wm_title('Unlock excel files v' + __version__)
root.columnconfigure(3, weight=1)
root.rowconfigure(5, weight=1)
# A SimpleNamespace is used to save widgets that need to be accessed later.
w = SimpleNamespace()
# First row
ttk.Label(root, text='(1)').grid(row=0, column=0, sticky='ew')
fb = ttk.Button(root, text="Select file", command=do_file)
fb.grid(row=0, column=1, columnspan=2, sticky="w")
w.fb = fb
fn = ttk.Label(root)
fn.grid(row=0, column=3, columnspan=2, sticky="ew")
w.fn = fn
# Second row
ttk.Label(root, text='(2)').grid(row=1, column=0, sticky='ew')
backup = tk.IntVar()
backup.set(0)
w.backup = backup
ttk.Checkbutton(root, text='backup', variable=backup,
command=on_backup).grid(row=1, column=1, sticky='ew')
suffixlabel = ttk.Label(root, text='suffix:')
suffixlabel['state'] = 'disabled'
suffixlabel.grid(row=1, column=2, sticky='ew')
w.suffixlabel = suffixlabel
suffix = tk.StringVar()
suffix.set('-orig')
w.suffix = suffix
se = ttk.Entry(root, justify='left', textvariable=suffix)
se.grid(row=1, column=3, columnspan=1, sticky='w')
se['state'] = 'disabled'
w.suffixentry = se
# Third row
ttk.Label(root, text='(3)').grid(row=2, column=0, sticky='ew')
gobtn = ttk.Button(root, text="Go!", command=do_start)
gobtn['state'] = 'disabled'
gobtn.grid(row=2, column=1, sticky='ew')
w.gobtn = gobtn
# Fourth row
ttk.Label(root, text='(4)').grid(row=3, column=0, sticky='ew')
ttk.Label(root, text='Progress:').grid(row=3, column=1, sticky='w')
# Fifth row
sb = tk.Scrollbar(root, orient="vertical")
status = tk.Listbox(root, width=40, yscrollcommand=sb.set)
status.grid(row=4, rowspan=5, column=1, columnspan=3, sticky="nsew")
w.status = status
sb.grid(row=4, rowspan=5, column=5, sticky="ns")
sb.config(command=status.yview)
# Ninth row
ttk.Button(root, text="Quit", command=do_exit).grid(row=9, column=1, sticky='ew')
# Return the widgets that need to be accessed.
return w
def create_state():
"""Create and initialize the global state."""
state = SimpleNamespace()
state.interval = 10
state.path = ''
state.inzf, state.outzf = None, None
state.infos = None
state.currinfo = None
state.worksheets_unlocked = 0
state.workbook_unlocked = False
state.directory = None
state.remove = None
return state
def statusmsg(text):
"""Append a message to the status listbox, and make sure it is visible."""
widgets.status.insert(tk.END, text)
widgets.status.see(tk.END)
# Step functions to call in the after() method.
def step_open_zipfiles():
path = widgets.fn['text']
state.path = path
statusmsg(f'Opening “{path}”...')
first, last = path.rsplit('.', maxsplit=1)
if widgets.backup.get():
backupname = first + widgets.suffix.get() + '.' + last
else:
backupname = first + '-orig' + '.' + last
state.remove = backupname
shutil.move(path, backupname)
state.inzf = zipfile.ZipFile(backupname, mode="r")
state.outzf = zipfile.ZipFile(
path, mode="w", compression=zipfile.ZIP_DEFLATED, compresslevel=1
)
root.after(state.interval, step_discover_internal_files)
def step_discover_internal_files():
statusmsg(f'Reading “{state.path}”...')
state.infos = [name for name in state.inzf.infolist()]
state.currinfo = 0
statusmsg(f'“{state.path}” contains {len(state.infos)} internal files.')
root.after(state.interval, step_filter_internal_file)
def step_filter_internal_file():
current = state.infos[state.currinfo]
stat = f'Processing “{current.filename}” ({state.currinfo+1}/{len(state.infos)})...'
statusmsg(stat)
# Doing the actual work
regex = None
data = state.inzf.read(current)
if b'sheetProtect' in data:
regex = r'<sheetProtect.*?/>'
statusmsg(f'Worksheet "{current.filename}" is protected.')
elif b'workbookProtect' in data:
regex = r'<workbookProtect.*?/>'
statusmsg('The workbook is protected')
else:
state.outzf.writestr(current, data)
if regex:
text = data.decode('utf-8')
newtext = re.sub(regex, '', text)
if len(newtext) != len(text):
state.outzf.writestr(current, newtext)
state.worksheets_unlocked += 1
statusmsg(f'Removed password from "{current.filename}".')
# Next iteration or next step.
state.currinfo += 1
if state.currinfo >= len(state.infos):
statusmsg('All internal files processed.')
state.currinfo = None
root.after(state.interval, step_close_zipfiles)
else:
root.after(state.interval, step_filter_internal_file)
def step_close_zipfiles():
statusmsg(f'Writing “{state.path}”...')
state.inzf.close()
state.outzf.close()
state.inzf, state.outzf = None, None
root.after(state.interval, step_finished)
def step_finished():
if state.remove:
os.chmod(state.remove, stat.S_IWRITE)
os.remove(state.remove)
state.remove = None
else:
statusmsg('Removing temporary file')
statusmsg(f'Unlocked {state.worksheets_unlocked} worksheets.')
statusmsg('Finished!')
widgets.gobtn['state'] = 'disabled'
widgets.fn['text'] = ''
state.path = ''
# Widget callbacks
def do_file():
"""Callback to open a file"""
if not state.directory:
state.directory = ''
available = [os.environ[k] for k in ('HOME', 'HOMEDRIVE') if k in os.environ]
if available:
state.directory = available[0]
fn = filedialog.askopenfilename(
title='Excel file to open',
parent=root,
defaultextension='.xlsx',
filetypes=(
('excel files', '*.xls*'), ('all files', '*.*')
),
)
if not fn:
return
state.directory = os.path.dirname(fn)
state.worksheets_unlocked = 0
state.workbook_unlocked = False
state.path = fn
widgets.fn['text'] = fn
widgets.gobtn['state'] = 'enabled'
widgets.status.delete(0, tk.END)
def on_backup():
if widgets.backup.get() == 1:
widgets.suffixlabel['state'] = 'enabled'
widgets.suffixentry['state'] = 'enabled'
else:
widgets.suffixlabel['state'] = 'disabled'
widgets.suffixentry['state'] = 'disabled'
def do_start():
root.after(state.interval, step_open_zipfiles)
def do_exit(arg=None):
"""
Callback to handle quitting.
"""
root.destroy()
if __name__ == '__main__':
# Detach from the command line on UNIX systems.
if os.name == 'posix':
if os.fork():
sys.exit() # Create the GUI window.
root = tk.Tk(None)
# Use a dialog window so that it floats even when using a tiling window
# manager.
root.attributes('-type', 'dialog')
# Don't show hidden files in the file dialog
# https://stackoverflow.com/questions/53220711/how-to-avoid-hidden-files-in-file-picker-using-tkinter-filedialog-askopenfilenam
try:
# call a dummy dialog with an impossible option to initialize the file
# dialog without really getting a dialog window; this will throw a
# TclError, so we need a try...except :
try:
root.tk.call('tk_getOpenFile', '-foobarbaz')
except tk.TclError:
pass
# now set the magic variables accordingly
root.tk.call('set', '::tk::dialog::file::showHiddenBtn', '1')
root.tk.call('set', '::tk::dialog::file::showHiddenVar', '0')
except Exception:
pass
# Widgets is a namespace of widgets that needs to be accessed by the callbacks.
# State is a namespace of the global state.
widgets = create_widgets(root)
state = create_state()
root.mainloop()
Then the version that uses threads:
"""Remove passwords from modern excel 2007+ files (xlsx, xlsm).
This is a multithreaded version of unlock-excel.pyw. All the work that was
there done in steps in the mainloop is now done in a single additional thread.
There is some confusion whether tkinter is thread-safe. That is, if one can
call tkinter functions and methods from any but the main thread. The
documentation for Python 3 says “yes”. Comments in the C source code for
tkinter say “its complicated” depending on how tcl is built. *Many* online
sources say “no”, but that could just be an echo chamber effect.
The author has tested this code on FreeBSD 12.1-STABLE amd64 using CPython
3.7.7 combined with a tcl built with threading enabled. There at least it
seems to work without problems.
"""
from types import SimpleNamespace
import os
import re
import shutil
import stat
import sys
import threading
import zipfile
from tkinter import filedialog
from tkinter import ttk
from tkinter.font import nametofont
import tkinter as tk
__version__ = "2020.04.27"
def create_widgets(root):
"""Create the window and its widgets.
Arguments:
root: the root window.
Returns:
A SimpleNamespace of widgets
"""
# Set the font.
default_font = nametofont("TkDefaultFont")
default_font.configure(size=12)
root.option_add("*Font", default_font)
# General commands and bindings
root.bind_all('q', do_exit)
root.wm_title('Unlock excel files v' + __version__)
root.columnconfigure(3, weight=1)
root.rowconfigure(5, weight=1)
# A SimpleNamespace is used to save widgets that need to be accessed later.
w = SimpleNamespace()
# First row
ttk.Label(root, text='(1)').grid(row=0, column=0, sticky='ew')
fb = ttk.Button(root, text="Select file", command=do_file)
fb.grid(row=0, column=1, columnspan=2, sticky="w")
w.fb = fb
fn = ttk.Label(root)
fn.grid(row=0, column=3, columnspan=2, sticky="ew")
w.fn = fn
# Second row
ttk.Label(root, text='(2)').grid(row=1, column=0, sticky='ew')
backup = tk.IntVar()
backup.set(0)
w.backup = backup
ttk.Checkbutton(root, text='backup', variable=backup,
command=on_backup).grid(row=1, column=1, sticky='ew')
suffixlabel = ttk.Label(root, text='suffix:')
suffixlabel['state'] = 'disabled'
suffixlabel.grid(row=1, column=2, sticky='ew')
w.suffixlabel = suffixlabel
suffix = tk.StringVar()
suffix.set('-orig')
w.suffix = suffix
se = ttk.Entry(root, justify='left', textvariable=suffix)
se.grid(row=1, column=3, columnspan=1, sticky='w')
se['state'] = 'disabled'
w.suffixentry = se
# Third row
ttk.Label(root, text='(3)').grid(row=2, column=0, sticky='ew')
gobtn = ttk.Button(root, text="Go!", command=do_start)
gobtn['state'] = 'disabled'
gobtn.grid(row=2, column=1, sticky='ew')
w.gobtn = gobtn
# Fourth row
ttk.Label(root, text='(4)').grid(row=3, column=0, sticky='ew')
ttk.Label(root, text='Progress:').grid(row=3, column=1, sticky='w')
# Fifth row
sb = tk.Scrollbar(root, orient="vertical")
status = tk.Listbox(root, width=60, yscrollcommand=sb.set)
status.grid(row=4, rowspan=5, column=1, columnspan=3, sticky="nsew")
w.status = status
sb.grid(row=4, rowspan=5, column=5, sticky="ns")
sb.config(command=status.yview)
# Ninth row
ttk.Button(root, text="Quit", command=do_exit).grid(row=9, column=1, sticky='ew')
# Return the widgets that need to be accessed.
return w
def create_state():
"""Create and initialize the global state."""
st = SimpleNamespace()
st.directory = None
return st
def statusmsg(text):
"""Append a message to the status listbox, and make sure it is visible."""
widgets.status.insert(tk.END, text)
widgets.status.see(tk.END)
def process_zipfile_thread():
"""Function to process a zip-file. This is to be run in a thread."""
path = widgets.fn['text']
statusmsg(f'Opening “{path}”...')
first, last = path.rsplit('.', maxsplit=1)
if widgets.backup.get():
backupname = first + widgets.suffix.get() + '.' + last
remove = None
else:
backupname = first + '-orig' + '.' + last
remove = backupname
shutil.move(path, backupname)
with zipfile.ZipFile(backupname, mode="r") as inzf, \
zipfile.ZipFile(
path, mode="w", compression=zipfile.ZIP_DEFLATED, compresslevel=1
) as outzf:
statusmsg(f'Reading “{path}”...')
infos = [name for name in inzf.infolist()]
statusmsg(f'“{path}” contains {len(infos)} internal files.')
worksheets_unlocked = 0
for idx, current in enumerate(infos, start=1):
smsg = f'Processing “{current.filename}” ({idx}/{len(infos)})...'
statusmsg(smsg)
# Doing the actual work
regex = None
data = inzf.read(current)
if b'sheetProtect' in data:
regex = r'<sheetProtect.*?/>'
statusmsg(f'Worksheet "{current.filename}" is protected.')
elif b'workbookProtect' in data:
regex = r'<workbookProtect.*?/>'
statusmsg('The workbook is protected')
else:
outzf.writestr(current, data)
if regex:
text = data.decode('utf-8')
newtext = re.sub(regex, '', text)
if len(newtext) != len(text):
outzf.writestr(current, newtext)
worksheets_unlocked += 1
statusmsg(f'Removed password from "{current.filename}".')
statusmsg('All internal files processed.')
statusmsg(f'Writing “{path}”...')
if remove:
os.chmod(remove, stat.S_IWRITE)
os.remove(remove)
else:
statusmsg('Removing temporary file')
statusmsg(f'Unlocked {state.worksheets_unlocked} worksheets.')
statusmsg('Finished!')
widgets.gobtn['state'] = 'disabled'
widgets.fn['text'] = ''
# Widget callbacks
def do_file():
"""Callback to open a file"""
if not state.directory:
state.directory = ''
available = [os.environ[k] for k in ('HOME', 'HOMEDRIVE') if k in os.environ]
if available:
state.directory = available[0]
fn = filedialog.askopenfilename(
title='Excel file to open',
parent=root,
defaultextension='.xlsx',
filetypes=(('excel files', '*.xls*'), ('all files', '*.*')),
)
if not fn:
return
state.directory = os.path.dirname(fn)
state.worksheets_unlocked = 0
state.workbook_unlocked = False
widgets.fn['text'] = fn
widgets.gobtn['state'] = 'enabled'
widgets.status.delete(0, tk.END)
def on_backup():
if widgets.backup.get() == 1:
widgets.suffixlabel['state'] = 'enabled'
widgets.suffixentry['state'] = 'enabled'
else:
widgets.suffixlabel['state'] = 'disabled'
widgets.suffixentry['state'] = 'disabled'
def do_start():
worker = threading.Thread(target=process_zipfile_thread)
worker.start()
def do_exit(arg=None):
"""
Callback to handle quitting.
"""
root.destroy()
if __name__ == '__main__':
# Detach from the command line on UNIX systems.
if os.name == 'posix':
if os.fork():
sys.exit()
# Create the GUI window.
root = tk.Tk(None)
# Use a dialog window so that it floats even when using a tiling window manager.
if os.name == 'posix':
root.attributes('-type', 'dialog')
# Don't show hidden files in the file dialog
# https://stackoverflow.com/questions/53220711/how-to-avoid-hidden-files-in-file-picker-using-tkinter-filedialog-askopenfilenam
try:
# call a dummy dialog with an impossible option to initialize the file
# dialog without really getting a dialog window; this will throw a
# TclError, so we need a try...except :
try:
root.tk.call('tk_getOpenFile', '-foobarbaz')
except tk.TclError:
pass
# now set the magic variables accordingly
root.tk.call('set', '::tk::dialog::file::showHiddenBtn', '1')
root.tk.call('set', '::tk::dialog::file::showHiddenVar', '0')
except Exception:
pass
# Widgets is a namespace of widgets that needs to be accessed by the callbacks.
# State is a namespace of the global state.
widgets = create_widgets(root)
state = create_state()
root.mainloop()
You can use threading.Thread to run a function.
threading.Thread it's like to open a new cpu thread to run the function
from threading import Thread
# Code....
Thread(target=function()).start
It has some differences between start and start(). start Starts executing the function If a some button or some command says tells the threading to run. But start() executes while the code running.
How to Handle a Button Click Event in Python? I am New to python and trying to develop Zip Extractor tool.i've handled the Btn1 and Btn2 Properly but the 3'rd one is giving me errors.("name res1 is not defined") Here is the code
i've Wrote as follows: Plz Help Me as i am a noobie :| Thanks In Adv :)
from tkinter import *
from tkinter.filedialog import askdirectory
import os, zipfile
extension = ".zip"
PASSWORD = "virus007"
global res1
global res2
window = Tk()
window.title("Welcome Zip_Extractor_Utility")
window.geometry('640x260')
lbl1 = Label(window, text="Select Source Location:" ,font=("Arial Bold", 12))
lbl2 = Label(window, text="Select Destination Location:" ,font=("Arial Bold", 12))
lbl1.grid(column=0, row=7)
lbl2.grid(column=50, row=7)
def clicked1():
res1 = askdirectory()
print(res1)
return res1
btn1 = Button(window, text="Browse" , command=clicked1)
btn1.grid(column=1, row=7)
def clicked2():
res2 = askdirectory()
print(res2)
return res2
btn2 = Button(window, text="Browse" , command=clicked2)
btn2.grid(column=51, row=7)
##lbl3 = Label(window, text="Extract:" ,font=("Arial ", 12))
##lbl3.grid(column=70, row=7)
def clicked3():
os.chdir(res1) # change directory from working dir to dir with files
for item in os.listdir(res1): # loop through items in dir
if item.endswith(extension): # check for ".zip" extension
file_name = os.path.abspath(item) # get full path of files
zip_ref = zipfile.ZipFile(file_name) # create zipfile object
zip_ref.setpassword(PASSWORD)
zip_ref.extractall(res2) # extract file to dir
zip_ref.close() # close file
#os.remove(file_name) # delete zipped file
print('done')
btn3 = Button(window, text="Extract" , command=clicked3)
btn3.grid(column=71, row=7)
window.mainloop()
In your case, just check if res1 and res2 is defined in clicked3 function. Maybe with 'res1' in vars() and 'res2' in vars(). If it's not defined, warn users that they need to specify source and destination folder first.
With my current code, it does not matter whether I click on "Input Folder" - Change or "JukeBox" change the result always gets displayed in "JukeBox" entry. This is incorrect, using class and self how can I change the code to display result from "Input Folder" - Change in "Input Folder" entry and the result from "Jukbox" - Change in "Jukebox" entry?
Also, how can I save the selected folders to a file so that it is there on app exit and re open?
My code:
import os
from tkinter import *
from tkinter import filedialog
inPut_dir = ''
jukeBox_dir = ''
def inPut():
opendir = filedialog.askdirectory(parent=root,initialdir="/",title='Input Folder')
inPut_dir = StringVar()
inPut_dir = os.path.abspath(opendir)
entry.delete(0, END)
entry.insert(0, inPut_dir)
def jukeBox():
opendir = filedialog.askdirectory(parent=root,initialdir="/",title='JukeBox')
jukeBox_dir = StringVar()
jukeBox_dir = os.path.abspath(opendir)
entry.delete(0, END)
entry.insert(0, jukeBox_dir)
root = Tk()
root.geometry("640x240")
root.title("Settings")
frametop = Frame(root)
framebottom = Frame(root)
frameright = Frame(framebottom)
text = Label(frametop, text="Input Folder").grid(row=5, column=2)
entry = Entry(frametop, width=50, textvariable=inPut_dir)
entry.grid(row=5,column=4,padx=2,pady=2,sticky='we',columnspan=20)
text = Label(frametop, text="JukeBox").grid(row=6, column=2)
entry = Entry(frametop, width=50, textvariable=jukeBox_dir)
entry.grid(row=6,column=4,padx=2,pady=2,sticky='we',columnspan=20)
ButtonA = Button(frametop, text="Change", command=inPut).grid(row=5, column=28)
ButtonB = Button(frametop, text="Change", command=jukeBox).grid(row=6, column=28)
ButtonC = Button(frameright, text="OK").grid(row=5, column=20, padx=10)
ButtonD = Button(frameright, text="Cancel").grid(row=5, column=15)
frametop.pack(side=TOP, fill=BOTH, expand=1)
framebottom.pack(side=BOTTOM, fill=BOTH, expand=1)
frameright.pack(side=RIGHT)
root.mainloop()
See attached image:enter image description here
Your code has both:
entry = Entry(frametop, width=50, textvariable=inPut_dir)
entry.grid(row=5,column=4,padx=2,pady=2,sticky='we',columnspan=20)
and
entry = Entry(frametop, width=50, textvariable=jukeBox_dir)
entry.grid(row=6,column=4,padx=2,pady=2,sticky='we',columnspan=20)
with jukeBox_dir/row 6 overriding inPut_dir/row 5
Therefore, in def input:
where you have:
entry.insert(0, inPut_dir)
You'll get the result in row 5 (jukebox_dir)
I am new to Python and obviously missing something important when working with checkbuttons. Here's the idea behind my program: I select a file manually and then, depending on whether the checkbox is checked or not, trigger either one calculation sequence or another using a button. To achieve this, I wanted to verify the state of the checkbox using the .get() command.
What I've found is that only one sequence is triggered all the time independently of the state of the checkbox. .get() is not updated when I click on the checkbox. What am I doing wrong? Any help will be greatly appreciated.
from tkinter import *
from tkinter import filedialog
import tkinter as tk
master = Tk()
root = tk.Tk()
col_sep = "\t"
col_h_b = [] # field column for background
col_m_b = [] # magnetization column for background
def choose_b_file():
root.fileName_b = filedialog.askopenfilename(filetypes=((".dat files", "*.dat"), ("All files", "*.*")))
with open(root.fileName_b, 'r') as f:
for line in f:
if line[0] != "#":
linedata = [float(line.split(col_sep)[i]) for i in range(len(line.split(col_sep)))]
col_h_b.append(linedata[4])
col_m_b.append(linedata[5])
print(f.name)
offset = BooleanVar()
checkbox = tk.Checkbutton(root, text="offset subtraction", variable=offset,onvalue=1, offvalue=0)
checkbox.pack()
def plot():
if offset.get() == 1:
#some mathematical operations and graph plotting
else:
#other mathematical operations and graph plotting
def close_window():
exit()
b_data = Button(master, text="Background", width=20, command=choose_b_file)
m_minus_b = Button(master, text="Plot", width=5, command=plot)
quit = Button(master, text="Quit", width=5, command=close_window)
b_data.pack()
m_minus_b.pack()
quit.pack()
root.mainloop()
You are mostly messing parents widgets root and master.
Do you need to have a separate window for the checkbox ?
Otherwise the quick fix is to replace root by master in the checkbox creation :
checkbox = tk.Checkbutton(root, text="offset subtraction" ...)
You can also simplify the boolean stuff, the default behavior for the checkbutton is to use 0 and 1, and remove the master or the root, choose only one.
from tkinter import *
from tkinter import filedialog
root = Tk()
col_sep = "\t"
col_h_b = [] # field column for background
col_m_b = [] # magnetization column for background
def choose_b_file():
root.fileName_b = filedialog.askopenfilename(filetypes=((".dat files", "*.dat"), ("All files", "*.*")))
with open(root.fileName_b, 'r') as f:
for line in f:
if line[0] != "#":
linedata = [float(line.split(col_sep)[i]) for i in range(len(line.split(col_sep)))]
col_h_b.append(linedata[4])
col_m_b.append(linedata[5])
print(f.name)
def plot():
if offset.get() == 1:
print('True')
#some mathematical operations and graph plotting
else:
print('False')
#other mathematical operations and graph plotting
def close_window():
exit()
offset = IntVar()
checkbox = Checkbutton(root, text="offset subtraction", variable=offset)
checkbox.pack()
b_data = Button(root, text="Background", width=20, command=choose_b_file)
m_minus_b = Button(root, text="Plot", width=5, command=plot)
quit = Button(root, text="Quit", width=5, command=close_window)
b_data.pack()
m_minus_b.pack()
quit.pack()
root.mainloop()
I'm trying to use messagebox.showinfo to show a message when my counter reach 4.
import tkinter
from tkinter import *
global cptBalle
global cptPrise
cptBalle = 0
cptPrise = 0
cptRetrait = 0
cptManche = 1
ptsVisiteur = 0
ptsReceveur = 0
coupSurVisiteur = 0
coupSurReceveur = 0
erreurVisiteur = 0
erreurReceveur = 0
equipeAuBaton = "visiteur"
def balle():
global cptBalle
global cptPrise
cptBalle += 1
if cptBalle == 4:
messagebox.showinfo(title="Balle", message="Testtest")
cptBalle = 0
cptPrise = 0
def prise():
pass
def fausse_balle():
pass
def retrait():
pass
def balle_passee():
pass
def mauvais_lancer():
pass
def sacrifice():
pass
def simple():
pass
def double():
pass
def triple():
pass
def circuit():
pass
def atteint():
pass
def erreur():
pass
def creer_bouton():
btnBalle = Button(app, text="Balle", command=balle)
btnBalle.grid(row=1, column=0)
btnPrise = Button(app, text="Prise", command=prise)
btnPrise.grid(row=2, column=0)
btnFausse_balle = Button(app, text="Fausse balle", command=fausse_balle)
btnFausse_balle.grid(row=3, column=0)
btnRetrait = Button(app, text="Retrait", command=retrait)
btnRetrait.grid(row=4, column=0)
btnBalle_passee = Button(app, text="Balle passee", command=balle_passee)
btnBalle_passee.grid(row=5, column=0)
btnMauvais_lancer = Button(app, text="Mauvais lancer", command=mauvais_lancer)
btnMauvais_lancer.grid(row=6, column=0)
btnSacrifice = Button(app, text="Sacrifice", command=sacrifice)
btnSacrifice.grid(row=7, column=0)
btnSimple = Button(app, text="Simple", command=simple)
btnSimple.grid(row=8, column=0)
btnDouble = Button(app, text="Double", command=double)
btnDouble.grid(row=9, column=0)
btnTriple = Button(app, text="Triple", command=triple)
btnTriple.grid(row=10, column=0)
btnCircuit = Button(app, text="Circuit", command=circuit)
btnCircuit.grid(row=11, column=0)
btnAtteint = Button(app, text="Atteint", command=atteint)
btnAtteint.grid(row=12, column=0)
btnErreur = Button(app, text="Erreur", command=erreur)
btnErreur.grid(row=13, column=0)
root = tkinter.Tk()
root.title("Baseball!")
root.geometry("750x350")
app = Frame(root)
app.grid()
creer_bouton()
root.mainloop()
The first button "btnBalle" call the function "Balle()".
It works when I run it in Python IDLE but when I use PyCharm, it doesn't.
Obviously that's not your whole program, but… let's assume your real program is calling Test() multiple times, but isn't actually starting the Tk runloop anywhere, or even creating a top-level Tk object. So, any Tkinter windows you try to display will never show up. (Actually, on some platforms, like OS X, it will show up—but it shouldn't, and if it doesn't on your platform, that's not a bug.)
Why does it work in IDLE? Because IDLE itself is written in Tkinter, and the tricks it uses to allow you to use the interactive interpreter while you've got a GUI program running also allow you to get away with this. That's not something you should rely on.
I ran into the same problem when attempting to use the messagebox class.
The basis of the code was:
import tkinter as tk
tk.messagebox.showinfo( --- )
I resolved the issue by adding:
from tkinter import messagebox
and then calling:
messagebox.showinfo( --- )
Hope this helps.