I've used Pythoncard to create my gui. Here it is in heavily condensed form:

import os
import sys
import os.path
import Tkinter
import wx
import subprocess
import subprocess as sp
from subprocess import Popen
from tkFileDialog import askopenfilenames
from tkFileDialog import askdirectory
import tkMessageBox
from Tkinter import *
from pathman import path
from PythonCard import dialog, model
from PythonCard.components import button, statictext, radiogroup



class VidToad(model.Background):
    
    def choosein(self, event):
        dlg = wx.DirDialog(self, "Choose Source folder...:", r'D:\\', style=wx.DD_DEFAULT_STYLE | wx.DD_DIR_MUST_EXIST)
        if dlg.ShowModal() == wx.ID_OK:
            global indirname
            indirname=os.path.normpath(dlg.GetPath())
            dlg.Destroy() 


    def on_radiogroup_select( self, event ) :
        global Formatname
        Formatname=self.components.radiogroup.stringSelection
        
                
 
    def on_Button1_mouseClick(self, event):
        if Formatname=="stretch":
            self.index_push()
            self.think()

My question is how can I make Button1 disabled once it has been clicked and another process (self.index_push(()has begun. Everything I've tried has given me attribute or similar errors. I still haven't quite got Python!
Thanks in advance!

Dani AI

Generated

Short answer: PythonCard exposes component attributes (dot notation) and includes an enabled boolean you can set; in other words, disable the button by changing its enabled property on the PythonCard component object. (pythoncard.sourceforge.net)

If self.index_push() is a long/blocking operation you must not run it on the GUI thread — do the disable, then start the work in a background thread and re-enable the button from the main thread when the work finishes. Use wx.CallAfter or post an event from the worker thread so the GUI update happens safely on the UI thread. Example pattern (short, illustrative):

# inside on_Button1_mouseClick
self.components.Button1.enabled = False
threading.Thread(target=self._worker_index_push).start()

def _worker_index_push(self):
    self.index_push()                       # long work (worker thread)
    wx.CallAfter(setattr, self.components.Button1, 'enabled', True)

See the PythonCard components docs for the enabled attribute and the wxPython long-running-tasks guidance for worker threads and wx.CallAfter. (pythoncard.sourceforge.net)

Troubleshooting tips tied to this thread: if you get AttributeError, confirm the component name from the resource file — PythonCard components are accessible as self.components.<name> (introspect with dir(self.components) or iterate its keys to discover the names). If the disable appears but the UI doesn't update, that's almost always because the UI thread is blocked; moving work to a thread or breaking it into chunks with wx.Yield/idle handlers fixes that. (stackoverflow.com)

This follows ’s point about needing the actual button object; in PythonCard that object is the entry in self.components, so set its enabled flag and use a thread + wx.CallAfter to keep the UI responsive. (pythoncard.sourceforge.net)

Recommended Answers

All 3 Replies

You have not declared Button1 in the code you posted so there is nothing to disable. But generally it is

b.config(state=DISABLED)

where "b" is the button's ID as returned by Tkinter. Also, you import Tkinter in two different ways (pick one only)

import Tkinter
from Tkinter import *

Do not mix wxPython and Tkinter

import Tkinter
import wx

"os.path" is available once you import os

import os
import os.path

And you only have to import subprocess once.

import subprocess
import subprocess as sp
from subprocess import Popen

One of Grayson's examples (click "He's dead" to disable)

from Tkinter import *

def disable_button():
    b1.config(state=DISABLED)

root = Tk()
root.title('Buttons')
Label(root, text="You shot him!").pack(pady=10)
b1=Button(root, text="He's dead!", command=disable_button)
b1.pack(side=LEFT)
Button(root, text="He's completely dead!", command=root.quit).pack(side=RIGHT)
root.mainloop()

You have not declared Button1 in the code you posted so there is nothing to disable.

This is Pythoncard so the button setup is contained in the resource file. As I understand it Python card is a "wrapper" or similar to wx, so I guess I should stick to wx. How would I disable the button in wx?
Thanks for all the tips on writing better code. I shall tidy it up now!

You have to have access to the button object and set enabled to False. I don't know of anyone here who uses PythonCard so we can't help much.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.