Is it possible to get rid of useless ok variable in this code?
cond1 = true
cond2 = true
cond3 = true
switch
when !cond1
console.log "cond1 failed"
when !cond2
console.log "cond2 failed"
when !cond3
console.log "cond3 failed"
else
ok = true
if !ok then process.exit(1)
console.log "good"
You may change your code to
cond1 = true
cond2 = true
cond3 = true
switch
when !cond1
console.log "cond1 failed"
when !cond2
console.log "cond2 failed"
when !cond3
console.log "cond3 failed"
process.exit(1) if !(cond1 && cond2 && cond3)
console.log "good"
with the disadvantage of duplicating the condition checking.
I guess that you want to show all unmet conditions (because you put the process.exit call after the switch statement). If so, your code has the problem that it does only shows the first unfulfilled condition. So I would just use if statements
cond1 = false
cond2 = false
cond3 = true
if !cond1
console.log "cond1 failed"
if !cond2
console.log "cond2 failed"
if !cond3
console.log "cond3 failed"
process.exit(1) if !(cond1 && cond2 && cond3)
console.log "good"
All over all you'll have to decide if the double checking of your conditions or one setting and checking of a variable is more expensive in comparison with the readability of your code.
I would give readability a higher priority if not realy dealing with performance or memory problems an use something like:
cond1 = false
cond2 = false
cond3 = true
error={"success":true,"msg":"good"}
addError=(msg)->
error.msg="" if error.success
error.success=false
error.msg+=msg+"\n"
checkForErrors=(e)->
console.log e.msg
if !e.success
process.exit(1)
addError "cond1 failed" if !cond1
addError "cond2 failed" if !cond2
addError "cond3 failed" if !cond3
checkForErrors error
If you should write the condition checking before or after the addError call depends of the length of your condition code.
Related
I'm new to coding and still learning about Python.
I have a task where I have to upload lines from Python to a text file and then verify the lines later in the code e.g. I have to input user names and user passwords and add to the text file as [user_name, user_pass].
My problem is that when I try to verify the line one of 2 things happen. After I added a split function for the line e.g. verified_user, verified_password = line.split(", ") it runs into an error stating that I do not have enough values for the request made e.g 2 expected, 1 made. If I change the split input and it does run, the verification loop states that my inputs does not match any lines in the string.
Every thing works if I add the information to the text file only. But the moment I add via the appendix action in Python it no longer works.
this is what I have so far:
user_list = []
all_names_entered = "no"
while all_names_entered == "no":
user_name = input("Enter user name: ")
user_pass = input("Enter password: ")
user_list.append(user_name + ", " + user_pass)
while True:
all_names_entered = input("All users entered?: ")
if all_names_entered in ['yes','no']:
break
else:
print( 'please answer with yes or no' )
for items in user_list:
with open('user.txt', 'a') as file:
file.write(f"{user_name}, {user_pass}\n")
print (user_list)
file.close()
the next block reads as follow:
user_file = open("user.txt", "r+")
login = False
while login == False:
username = input("Enter user name: ")
password = input("Enter user password: ")
for line in user_file:
other = line.strip()
valid_user, valid_password = line.split(", ")
if username == valid_user and password == valid_password:
login = True
print ("You have successfully logged in")
break
else:
print("You have entered incorrect detail. Please try again")
user_file.seek(0)
user_file.close()
Firstly, indentation is important in Python.
Secondly, you're supposed to loop if user enters 'no'.
Utilize the item that's initialized in each for loop.
You initialized other but it was never consumed.
Following is code for writing into file:
user_list = []
all_names_entered = "no"
while all_names_entered == "no":
user_name = input("Enter user name: ")
user_pass = input("Enter password: ")
user_list.append(user_name + ", " + user_pass)
query_all_names_entered = True
while query_all_names_entered:
all_names_entered = input("All users entered?: ")
if all_names_entered == 'yes':
query_all_names_entered = False
break
elif all_names_entered == 'no':
query_all_names_entered = False
continue
else:
print('Please answer with yes or no')
all_names_entered = "no"
with open('user.txt', 'a') as file:
for item in user_list:
file.write(f"{item}\n")
print (user_list)
file.close()
And following is for reading file to log in:
user_file = open("user.txt", "r+")
login = False
lines = user_file.readlines()
while login == False:
username = input("Enter user name: ")
password = input("Enter user password: ")
for line in lines:
valid_user, valid_password = line.strip().split(", ")
if username == valid_user and password == valid_password:
login = True
print ("You have successfully logged in")
break
if login == False: print ("You have entered incorrect detail. Please try again")
user_file.close()
We are using Magento 2 with Varnish cache
We only get Varnish Cache HIT on very few /catalogsearch/result/ pages, and we really can not figure out why we don't get cache HIT on all /catalogsearch/result/ pages.
Please help us in the right direction :-)
Ex.
we always get HIT on this url
https://www.babygear.dk/catalogsearch/result/?q=bog
We always get MISS on a lot of other search queries
https://www.babygear.dk/catalogsearch/result/?q=black
https://www.babygear.dk/catalogsearch/result/?q=box
https://www.babygear.dk/catalogsearch/result/?q=box
Here is our varnish.vlc
# VCL version 5.0 is not supported so it should be 4.0 even though actually used Varnish version is 5
vcl 4.0;
import std;
# The minimal Varnish version is 5.0
# For SSL offloading, pass the following header in your proxy server or load balancer: 'X-Forwarded-Proto: https'
backend default {
.host = "127.0.0.1";
.port = "8080";
.first_byte_timeout = 600s;
}
acl purge {
"127.0.0.1";
}
sub vcl_recv {
if (req.method == "PURGE") {
if (client.ip !~ purge) {
return (synth(405, "Method not allowed"));
}
# To use the X-Pool header for purging varnish during automated deployments, make sure the X-Pool header
# has been added to the response in your backend server config. This is used, for example, by the
# capistrano-magento2 gem for purging old content from varnish during it's deploy routine.
if (!req.http.X-Magento-Tags-Pattern && !req.http.X-Pool) {
return (synth(400, "X-Magento-Tags-Pattern or X-Pool header required"));
}
if (req.http.X-Magento-Tags-Pattern) {
ban("obj.http.X-Magento-Tags ~ " + req.http.X-Magento-Tags-Pattern);
}
if (req.http.X-Pool) {
ban("obj.http.X-Pool ~ " + req.http.X-Pool);
}
return (synth(200, "Purged"));
}
if (req.method != "GET" &&
req.method != "HEAD" &&
req.method != "PUT" &&
req.method != "POST" &&
req.method != "TRACE" &&
req.method != "OPTIONS" &&
req.method != "DELETE") {
/* Non-RFC2616 or CONNECT which is weird. */
return (pipe);
}
# We only deal with GET and HEAD by default
if (req.method != "GET" && req.method != "HEAD") {
return (pass);
}
# Bypass shopping cart, checkout
if (req.url ~ "/checkout") {
return (pass);
}
# Bypass health check requests
if (req.url ~ "/pub/health_check.php") {
return (pass);
}
# Set initial grace period usage status
set req.http.grace = "none";
# normalize url in case of leading HTTP scheme and domain
set req.url = regsub(req.url, "^http[s]?://", "");
# collect all cookies
std.collect(req.http.Cookie);
# Compression filter. See https://www.varnish-cache.org/trac/wiki/FAQ/Compression
if (req.http.Accept-Encoding) {
if (req.url ~ "\.(jpg|jpeg|png|gif|gz|tgz|bz2|tbz|mp3|ogg|swf|flv)$") {
# No point in compressing these
unset req.http.Accept-Encoding;
} elsif (req.http.Accept-Encoding ~ "gzip") {
set req.http.Accept-Encoding = "gzip";
} elsif (req.http.Accept-Encoding ~ "deflate" && req.http.user-agent !~ "MSIE") {
set req.http.Accept-Encoding = "deflate";
} else {
# unknown algorithm
unset req.http.Accept-Encoding;
}
}
# Remove all marketing get parameters to minimize the cache objects
if (req.url ~ "(\?|&)(gclid|ff|fp|cx|ie|cof|siteurl|zanpid|origin|fbclid|mc_[a-z]+|utm_[a-z]+|_bta_[a-z]+)=") {
set req.url = regsuball(req.url, "(gclid|ff|fp|cx|ie|cof|siteurl|zanpid|origin|fbclid|mc_[a-z]+|utm_[a-z]+|_bta_[a-z]+)=[-_A-z0-9+()%.]+&?", "");
set req.url = regsub(req.url, "[?|&]+$", "");
}
# Static files caching
if (req.url ~ "^/(pub/)?(media|static)/") {
# Static files should not be cached by default
#return (pass);
# But if you use a few locales and don't use CDN you can enable caching static files by commenting previous line (#return (pass);) and uncommenting next 3 lines
unset req.http.Https;
unset req.http.X-Forwarded-Proto;
unset req.http.Cookie;
}
return (hash);
}
sub vcl_hash {
if (req.http.cookie ~ "X-Magento-Vary=") {
hash_data(regsub(req.http.cookie, "^.*?X-Magento-Vary=([^;]+);*.*$", "\1"));
}
# For multi site configurations to not cache each other's content
if (req.http.host) {
hash_data(req.http.host);
} else {
hash_data(server.ip);
}
# To make sure http users don't see ssl warning
if (req.http.X-Forwarded-Proto) {
hash_data(req.http.X-Forwarded-Proto);
}
if (req.url ~ "/graphql") {
call process_graphql_headers;
}
}
sub process_graphql_headers {
if (req.http.Store) {
hash_data(req.http.Store);
}
if (req.http.Content-Currency) {
hash_data(req.http.Content-Currency);
}
}
sub vcl_backend_response {
set beresp.grace = 3d;
if (beresp.http.content-type ~ "text") {
set beresp.do_esi = true;
}
if (bereq.url ~ "\.js$" || beresp.http.content-type ~ "text") {
set beresp.do_gzip = true;
}
if (beresp.http.X-Magento-Debug) {
set beresp.http.X-Magento-Cache-Control = beresp.http.Cache-Control;
}
# cache only successfully responses
if (beresp.status != 200) {
set beresp.ttl = 0s;
set beresp.uncacheable = true;
return (deliver);
} elsif (beresp.http.Cache-Control ~ "private") {
set beresp.uncacheable = true;
set beresp.ttl = 44400s;
return (deliver);
}
# validate if we need to cache it and prevent from setting cookie
if (beresp.ttl > 0s && (bereq.method == "GET" || bereq.method == "HEAD")) {
unset beresp.http.set-cookie;
}
# If page is not cacheable then bypass varnish for 2 minutes as Hit-For-Pass
if (beresp.ttl <= 0s ||
beresp.http.Surrogate-control ~ "no-store" ||
(!beresp.http.Surrogate-Control &&
beresp.http.Cache-Control ~ "no-cache|no-store") ||
beresp.http.Vary == "*") {
# Mark as Hit-For-Pass for the next 2 minutes
set beresp.ttl = 120s;
set beresp.uncacheable = true;
}
return (deliver);
}
sub vcl_deliver {
if (resp.http.X-Magento-Debug) {
if (resp.http.x-varnish ~ " ") {
set resp.http.X-Magento-Cache-Debug = "HIT";
set resp.http.Grace = req.http.grace;
} else {
set resp.http.X-Magento-Cache-Debug = "MISS";
}
} #else {
# unset resp.http.Age;
# }
# Not letting browser to cache non-static files.
if (resp.http.Cache-Control !~ "private" && req.url !~ "^/(pub/)?(media|static)/") {
set resp.http.Pragma = "no-cache";
set resp.http.Expires = "-1";
set resp.http.Cache-Control = "no-store, no-cache, must-revalidate, max-age=0";
}
unset resp.http.X-Magento-Debug;
unset resp.http.X-Magento-Tags;
unset resp.http.X-Powered-By;
unset resp.http.Server;
unset resp.http.X-Varnish;
unset resp.http.Via;
unset resp.http.Link;
}
sub vcl_hit {
if (obj.ttl >= 0s) {
# Hit within TTL period
return (deliver);
}
if (std.healthy(req.backend_hint)) {
if (obj.ttl + 3000000s > 0s) {
# Hit after TTL expiration, but within grace period
set req.http.grace = "normal (healthy server)";
return (deliver);
} else {
# Hit after TTL and grace expiration
return (miss);
}
} else {
# server is not healthy, retrieve from cache
set req.http.grace = "unlimited (unhealthy server)";
return (deliver);
}
}
It's a bit tough to judge what's really going on, because there's both a Varnish cache in front of Magento and Cloudflare as the CDN.
A no-cache/no-store Cache-Control value
What I am seeing in general for your searches, is the following Cache-Control value:
cache-control: no-store, no-cache, must-revalidate, max-age=0
Based on this value, Varnish will decide not to cache. In the response headers of must of your search results you will see that Age: 0 is set. This means that Varnish doesn't hold the value in cache.
A cached search result that shouldn't be cacheable
However, weirdly enough https://www.babygear.dk/catalogsearch/result/?q=bog does have a an Age header with a value greater than zero:
age: 38948
This means it's been in cache for 38948 seconds. But really, this shouldn't be happening, because the page is not supposed to be cacheable.
Making search results cacheable:
Please make sure you have a Cache-Control header that allows caching, if you want to cache search results.
Example:
Cache-Control: public, s-maxage=3600
Debugging using Varnishlog
If you really want to know what happens in behind the scenes in Varnish, you can perform some debugging using the varnishlog binary.
You could run the following command to get debug output:
varnishlog -g request -q "ReqUrl eq '/catalogsearch/result/\?q=bog'"
This will print some very verbose logs on how Varnish treats the URL that causes the hit. You can add this output to your question, and I can try to examine what's going on.
FYI: I wrote a very detailed blog post about varnishlog a couple of years ago. Please go to https://feryn.eu/blog/varnishlog-measure-varnish-cache-performance/ to have a look, and to learn.
What's Cloudflare doing?
All that being said, I have no clue what the impact of Cloudflare is on the cacheability of the website. The varnishlog output will give us some insight, but if those results diverge from reality, Cloudflare is probably getting in our way.
Keep this in mind while debugging.
Inside vcl_recv Add
# Bypass search requests
if (req.url ~ "/catalogsearch") {
return (pass);
}
check .htaccess file for Cache-Control setting.
I am trying to add a procedure to pop-up a modal dialog inside a plug-in.
Its purpose is to query a response at designated steps within the control-flow of the plug-in (not just acquire parameters at its start).
I have tried using gtk - I get a dialog but it is asynchronous - the plugin continues execution. It needs to operate as a synchronous function.
I have tried registering a plugin in order to take advantage of the gimpfu start-up dialogue for same. By itself, it works; it shows up in the procedural db when queried. But I never seem to be able to actually invoke it from within another plug-in - its either an execution error or wrong number of arguments no matter how many permutations I try.
[Reason behind all of this nonsense: I have written a lot of extension Python scripts for PaintShopPro. I have written a App package (with App.Do, App.Constants, Environment and the like that lets me begin to port those scripts to GIMP -- yes it is perverse, and yes sometimes the code just has to be rewritten, but for a lot of what I actual use in the PSP.API it is sufficient.
However, debugging and writing the module rhymes with witch. So. I am trying to add emulation of psp's "SetExecutionMode" (ie interactive). If
set, the intended behavior is that the App.Do() method will "pause" after/before it runs the applicable psp emulation code by popping up a simple message dialog.]
A simple modal dialogue within a gimp python-fu plug-in can be implemented via gtk's Dialog interface, specifically gtk.MessageDialog.
A generic dialog can be created via
queryDialogue = gtk.MessageDialog(None, gtk.DIALOG_DESTROY_WITH_PARENT \
gtk.MESSAGE_QUESTION, \
gtk.BUTTONS_OK_CANCEL, "")
Once the dialog has been shown,
a synchronous response may be obtained from it
queryDialogue.show()
response = queryDialogue.run()
queryDialogue.hide()
The above assumes that the dialog is not created and thence destroyed after each use.
In the use case (mentioned in the question) of a modal dialog to manage single stepping through a pspScript in gimp via an App emulator package, the dialogue message contents need to be customized for each use. [Hence, the "" for the message argument in the Constructor. [more below]]
In addition, the emulator must be able to accept a [cancel] response to 'get out of Dodge' - ie quit the entire plug-in (gracefully). I could not find a gimpfu interface for the latter, (and do not want to kill the app entirely via gimp.exit()). Hence, this is accomplished by raising a custom Exception class [appTerminate] within the App pkg and catching the exception in the outer-most scope of the plugin. When caught, then, the plug-in returns (exits).[App.Do() can not return a value to indicate continue/exit/etc, because the pspScripts are to be included verbatim.]
The following is an abbreviated skeleton of the solution -
a plug-in incorporating (in part) a pspScript
the App.py pkg supplying the environment and App.Do() to support the pspScript
a Map.py pkg supporting how pspScripts use dot-notation for parameters
App.py demonstrates creation, customization and use of a modal dialog - App.doContinue() displays the dialogue illustrating how it can be customized on each use.
App._parse() parses the pspScript (excerpt showing how it determines to start/stop single-step via the dialogue)
App._exec() implements the pspScript commands (excerpt showing how it creates the dialogue, identifies the message widget for later customization, and starts/stops its use)
# App.py (abbreviated)
#
import gimp
import gtk
import Map # see https://stackoverflow.com/questions/2352181/how-to- use-a-dot-to-access-members-of-dictionary
from Map import *
pdb = gimp.pdb
isDialogueAvailable = False
queryDialogue = None
queryMessage = None
Environment = Map({'executionMode' : 1 })
_AutoActionMode = Map({'Match' : 0})
_ExecutionMode = Map({'Default' : 0}, Silent=1, Interactive=2)
Constants = Map({'AutoActionMode' : _AutoActionMode}, ExecutionMode=_ExecutionMode ) # etc...
class appTerminate(Exception): pass
def Do(eNvironment, procedureName, options = {}):
global appTerminate
img = gimp.image_list()[0]
lyr = pdb.gimp_image_get_active_layer(img)
parsed = _parse(img, lyr, procedureName, options)
if eNvironment.executionMode == Constants.ExecutionMode.Interactive:
resp = doContinue(procedureName, parsed.detail)
if resp == -5: # OK
print procedureName # log to stdout
if parsed.valid:
if parsed.isvalid:
_exec(img, lyr, procedureName, options, parsed, eNvironment)
else:
print "invalid args"
else:
print "invalid procedure"
elif resp == -6: # CANCEL
raise appTerminate, "script cancelled"
pass # terminate plugin
else:
print procedureName + " skipped"
pass # skip execution, continue
else:
_exec(img, lyr, procedureName, options, parsed, eNvironment)
return
def doContinue(procedureName, details):
global queryMessage, querySkip, queryDialogue
# - customize the dialog -
if details == "":
msg = "About to execute procedure \n "+procedureName+ "\n\nContinue?"
else:
msg = "About to execute procedure \n "+procedureName+ "\n\nDetails - \n" + details +"\n\nContinue?"
queryMessage.set_text(msg)
queryDialogue.show()
resp = queryDialogue.run() # get modal response
queryDialogue.hide()
return resp
def _parse(img, lyr, procedureName, options):
# validate and interpret App.Do options' semantics vz gimp
if procedureName == "Selection":
isValid=True
# ...
# parsed = Map({'valid' : True}, isvalid=True, start=Start, width=Width, height=Height, channelOP=ChannelOP ...
# /Selection
# ...
elif procedureName == "SetExecutionMode":
generalOptions = options['GeneralSettings']
newMode = generalOptions['ExecutionMode']
if newMode == Constants.ExecutionMode.Interactive:
msg = "set mode interactive/single-step"
else:
msg = "set mode silent/run"
parsed = Map({'valid' : True}, isvalid=True, detail=msg, mode=newMode)
# /SetExecutionMode
else:
parsed = Map({'valid' : False})
return parsed
def _exec(img, lyr, procedureName, options, o, eNvironment):
global isDialogueAvailable, queryMessage, queryDialogue
#
try:
# -------------------------------------------------------------------------------------------------------------------
if procedureName == "Selection":
# pdb.gimp_rect_select(img, o.start[0], o.start[1], o.width, o.height, o.channelOP, ...
# /Selection
# ...
elif procedureName == "SetExecutionMode":
generalOptions = options['GeneralSettings']
eNvironment.executionMode = generalOptions['ExecutionMode']
if eNvironment.executionMode == Constants.ExecutionMode.Interactive:
if isDialogueAvailable:
queryDialogue.destroy() # then clean-up and refresh
isDialogueAvailable = True
queryDialogue = gtk.MessageDialog(None, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_QUESTION, gtk.BUTTONS_OK_CANCEL, "")
queryDialogue.set_title("psp/APP.Do Emulator")
queryDialogue.set_size_request(450, 180)
aqdContent = queryDialogue.children()[0]
aqdHeader = aqdContent.children()[0]
aqdMsgBox = aqdHeader.children()[1]
aqdMessage = aqdMsgBox.children()[0]
queryMessage = aqdMessage
else:
if isDialogueAvailable:
queryDialogue.destroy()
isDialogueAvailable = False
# /SetExecutionMode
else: # should not get here (should have been screened by parse)
raise AssertionError, "unimplemented PSP procedure: " + procedureName
except:
raise AssertionError, "App.Do("+procedureName+") generated an exception:\n" + sys.exc_info()
return
A skeleton of the plug-in itself. This illustrates incorporating a pspScript which includes a request for single-step/interactive execution mode, and thus the dialogues. It catches the terminate exception raised via the dialogue, and then terminates.
def generateWebImageSet(dasImage, dasLayer, title, mode):
try:
img = dasImage.duplicate()
# ...
bkg = img.layers[-1]
frameWidth = 52
start = bkg.offsets
end = (start[0]+bkg.width, start[1]+frameWidth)
# pspScript: (snippet included verbatim)
# SetExecutionMode / begin interactive single-step through pspScript
App.Do( Environment, 'SetExecutionMode', {
'GeneralSettings': {
'ExecutionMode': App.Constants.ExecutionMode.Interactive
}
})
# Selection
App.Do( Environment, 'Selection', {
'General' : {
'Mode' : 'Replace',
'Antialias' : False,
'Feather' : 0
},
'Start': start,
'End': end
})
# Promote
App.Do( Environment, 'SelectPromote' )
# und_so_weiter ...
except App.appTerminate:
raise AssertionError, "script cancelled"
# /generateWebImageSet
# _generateFloatingCanvasSetWeb.register -----------------------------------------
#
def generateFloatingCanvasSetWeb(dasImage, dasLayer, title):
mode="FCSW"
generateWebImageSet(dasImage, dasLayer, title, mode)
register(
"generateFloatingCanvasSetWeb",
"Generate Floating- Frame GW Canvas Image Set for Web Page",
"Generate Floating- Frame GW Canvas Image Set for Web Page",
"C G",
"C G",
"2019",
"<Image>/Image/Generate Web Imagesets/Floating-Frame Gallery-Wrapped Canvas Imageset...",
"*",
[
( PF_STRING, "title", "title", "")
],
[],
generateFloatingCanvasSetWeb)
main()
I realize that this may seem like a lot of work just to be able to include some pspScripts in a gimp plug-in, and to be able to single-step through the emulation. But we are talking about maybe 10K lines of scripts (and multiple scripts).
However, if any of this helps anyone else with dialogues inside plug-ins, etc., so much the better.
I'm new to coffeescript and I'm not sure what is wrong with my syntax. I want to add an error message if either the date or time field is empty upon clicking the update button. Here is my code.
$.add_error = (field, message) ->
unless field.hasClass('input-error')
field.after('<span class="input-error-message">' + message + '</span>')
field.addClass('input-error')
$.remove_error = (field) ->
field.removeClass('input-error')
field.parent().find('.input-error-message').remove()
$('.btn.update_schedule').click ->
date = $('#date')
time = $('#time')
if (date.val() && !time.val()) || (!date.val() && time.val())
if !time.val()
$.add_error(repeat_count, 'Please select both a date and time')
false
else !date.val()
$.add_error(repeat_date, 'Please select both a date and time')
false
else
$.remove_error(time) || $.remove_error(date)
I'm unable to compile this code because it says there's an unexpected indentation but I don't see it. Any advice would be greatly appreciated.
In the last block $('.btn.update_schedule').click ->, there is an
if ... else ... else ...
that is basically non-sense.
It seems that should be instead an
if ... else if ... else ...
This seems the correct version:
$('.btn.update_schedule').click ->
date = $('#date')
time = $('#time')
if (date.val() && !time.val()) || (!date.val() && time.val())
if !time.val()
$.add_error(repeat_count, 'Please select both a date and time')
false
else if !date.val()
$.add_error(repeat_date, 'Please select both a date and time')
false
else
$.remove_error(time) || $.remove_error(date)
I'm absolute beginner for python Tkinter. My program has serial port and TCP client socket connection (Running in thread). It's running well in console application but not work in Tkinter GUI.
count = 0
initialState = True
def initState(reader, ReaderName, readerType, serialport, baud, databit, readerPacket):
global count
global initialState
if initialState:
while not reader.SettingReader(ReaderName, readerType, serialport, baud, databit, readerPacket):
count += 1
count = 0
labelSearching.place(x=290, y=260)
labelReaderSetting.configure(image=readerSettingSuccess)
app.update_idletasks()
labelSearching.grid_forget()
labelReaderConnect.place(x=290, y=260)
app.update_idletasks()
labelReaderConnect.configure(image=readerConnected)
labelServerConnect.place(x=290, y=320)
app.update_idletasks()
while not reader.StartServer():
count += 1
count = 0
labelServerConnect.configure(image=serverConnected)
app.update_idletasks()
labelContainer.grid_forget()
labelReaderSetting.configure(image=readerSettingSuccessSmall)
labelReaderSetting.place(x=80, y=200)
labelReaderSetting.lift()
labelReaderConnect.configure(image=readerConnectedSmall)
labelReaderConnect.place(x=80, y=260)
labelReaderConnect.lift()
labelServerConnect.configure(image=serverConnectedSmall)
labelServerConnect.place(x=80, y=320)
labelServerConnect.lift()
labelWaitingTap.place(x=460, y=260)
labelLeft.grid(row=1, column=0)
labelRight.grid(row=1, column=1)
app.update_idletasks()
reader.SaveSettingToFile()
initialState = False
else:
runnMainProgram(reader)
app.update()
app.after(1000, functools.partial(initState, reader, ReaderName, readerType, serialport, baud, databit, readerPacket))
def runnMainProgram(reader):
try:
check = reader.StartReader(reader._CARDANDPASSWORD)
app.update_idletasks()
if check == True:
print "Open the door"
check = ""
print "Ready..."
app.update_idletasks()
elif check == False:
print "Doesn't Open The Door"
check = ""
print "Ready..."
app.update_idletasks()
elif check == 2:
print "Reader disconnect"
print "Reconnecting to Reader"
reader.ClosePort()
while not reader.OpenPort():
count += 1
count = 0
check = ""
print "Ready..."
app.update_idletasks()
except KeyboardInterrupt:
exit()
app.after(10, functools.partial(runnMainProgram, reader))
app = Tk()
app.title("Access Control")
app.geometry('800x610+200+50')
app.protocol('WM_DELETE_WINDOW', closewindow)
updateGUIThread = threading.Thread(target=updateGUI)
app.minsize('800', '610')
app.maxsize('800', '610')
"I'm create Tkinter widget here."
reader = Readers()
settingList = list()
readerType = ""
readerPacket = ""
try:
for line in fileinput.FileInput("Setting.txt", mode='r'):
settingList.append(line)
if str(line).find("DF760MSB", 0, len(str(line))) >= 0:
readerType = reader._DF760MSB
elif str(line).find("DF760LSB", 0, len(str(line))) >= 0:
readerType = reader._DF760LSB
else:
readerType = reader._DF760MSB
if str(line).find("SINGLEPACKET", 0, len(str(line))) >= 0:
readerPacket = reader.SINGLEPACKET
elif str(line).find("MULTIPACKET", 0, len(str(line))) >= 0:
readerPacket = reader.MULTIPACKETS
else:
readerPacket = reader.SINGLEPACKET
ReaderName = str(settingList[0]).rstrip()
baud = int(settingList[1])
databit = int(settingList[2])
HOST = str(settingList[3]).rstrip()
PORT = int(settingList[4])
TIMEOUT = int(settingList[5])
except:
ReaderName = "R001"
baud = 19200
databit = 8
HOST = "10.50.41.81"
PORT = 43
TIMEOUT = 10
serialport = 'COM3'
reader.SettingServer(HOST, PORT, TIMEOUT)
app.after(100, functools.partial(initState, reader, ReaderName, readerType, serialport, baud, databit, readerPacket))
app.mainloop()
when I'm run this code GUI will freezing but serial port and TCP client socket still running.
I've try to fix this problem (looking in every where) but I'm got nothing. Any idea? Thank so much.
The way to solve this would be to call app.after(100, <methodName>) from the receiving thread. This stops the main thread from being blocked by waiting for a signal, but also means that tkinter can update instantly too as the method pushed to .after will be executed in the main thread. By specifying 100 as the time frame, it will appear to change nigh on instantly as the argument passed is the number of milliseconds.