I have the following Python MFC code. I have a listbox which I fill with some values, and when the user clicks on the values I want the static text control to be updated with the current selection. There are two problems with this code. The first is that the value in the text control is only updated the first time I click on the listbox. The second is that the value lags behind the real selected value in the listbox, presumably because the control handles the click after my handler code gets called. I'd appreciate help with either of these issues.
An odd thing, (perhaps a clue) is that when I mouse-down over the 'OK' button but move away for mouse-up the static text does get updated as I would expect.
I've tried RedrawWindow(), UpdateWindow(), ShowWindow() on both the control and the dialog, and nothing seems to make any difference.
import win32con
from pywin.mfc import dialog
IDC_LIST = 9000
IDC_TEXT = 9001
class ChooserDialog(dialog.Dialog):
def __init__(self):
DIALOGTEMPLATE = [
["Test", (0, 0, 254, 199), win32con.WS_CAPTION | win32con.DS_MODALFRAME, None, (8, "MS SansSerif")],
[128, "OK", win32con.IDOK, (197,178,50,14), win32con.BS_PUSHBUTTON | win32con.WS_VISIBLE],
["listbox", "List", IDC_LIST, (7,7,177,186), win32con.WS_VISIBLE],
["static", "", IDC_TEXT, (197,7,50,160), win32con.WS_CHILD | win32con.WS_VISIBLE]
]
dialog.Dialog.__init__(self, DIALOGTEMPLATE)
def OnInitDialog(self):
rc = dialog.Dialog.OnInitDialog(self)
for i in ["one", "two", "three"]:
self.GetDlgItem(IDC_LIST).AddString(i)
self.HookCommand(self.OnNotify, IDC_LIST)
return rc
def OnNotify(self, ctrl, action):
if ctrl == IDC_LIST:
selected = self.GetDlgItem(IDC_LIST).GetCurSel()
self.SetDlgItemText(IDC_TEXT, "%d" % selected)
self.GetDlgItem(IDC_TEXT).RedrawWindow()
return 1
dia = ChooserDialog()
dia.DoModal()
The first problem with the code was that the win32con.LBS_NOTIFY style wasn't set for the listbox control. If that isn't set you won't get any messages from the LB. The few messages that I was getting were due to other events in the dialog.
The second problem was that I was using HookCommand(), which intercepts commands, and allows you to handle them. Instead I wanted HookMessage() to get only the notifications. It seems notifications get called after the update of the control, so that's exactly what I wanted.
The LBN_SELCHANGE notification, according to MSDN documentation is received through the WM_COMMAND message. It seems I must subscribe to all WM_COMMAND messages in the dialog, and then filter them in my handler. The LBN_SELCHANGE documentation explains about what is passed, and in conjunction with the HookMessage() Python documentation you can work out how to handle it.
Here is the working code:
import win32con
from pywin.mfc import dialog
IDC_LIST = 9500
IDC_TEXT = 9501
class ChooserDialog(dialog.Dialog):
def __init__(self):
DIALOGTEMPLATE = [
["Test", (0, 0, 254, 199), win32con.WS_CAPTION | win32con.DS_MODALFRAME, None, (8, "MS SansSerif")],
[128, "OK", win32con.IDOK, (197,178,50,14), win32con.BS_PUSHBUTTON | win32con.WS_VISIBLE],
["listbox", "List", IDC_LIST, (7,7,177,186), win32con.WS_VISIBLE|win32con.LBS_NOTIFY],
["static", "", IDC_TEXT, (197,7,50,160), win32con.WS_CHILD | win32con.WS_VISIBLE]
]
dialog.Dialog.__init__(self, DIALOGTEMPLATE)
def OnInitDialog(self):
rc = dialog.Dialog.OnInitDialog(self)
for i in ["one", "two", "three"]:
self.GetDlgItem(IDC_LIST).AddString(i)
self.HookMessage(self.OnNotifyCommand, win32con.WM_COMMAND)
return rc
def OnNotifyCommand(self, data):
msg_id = data[1] # should always be WM_COMMAND
wParam = data[2]
lParam = data[3]
list_id = wParam & 0xffff
notification_code = (wParam & 0xffff0000) >> 16
if list_id != IDC_LIST: return # not our list box.
if notification_code != win32con.LBN_SELCHANGE: return # Not a change of selection
selected = self.GetDlgItem(IDC_LIST).GetCurSel()
self.SetDlgItemText(IDC_TEXT, "%d"%selected)
dia = ChooserDialog()
dia.DoModal()
Related
I want to activate command link button if at least one element is checked in a treeview.
I tried this method but it is not working well :
def activate_launch_button(self):
model = self.scenarios.model()
checked_indexes = model.match(model.index(0, 0), QtCore.Qt.CheckStateRole,QtCore.Qt.Checked, -1,QtCore.Qt.MatchExactly | QtCore.Qt.MatchRecursive)
print checked_indexes
if checked_indexes != []:
self.launch_btn.setEnabled(True)
The problem with this method is the button is activated only after closing the window. I don't understand why.
For caling this method I put it in two methods :
def show(self):
self.project.load()
if self.project.tranus_project:
self.tranus_folder.setText(self.project.tranus_project.path)
self.activate_launch_button()
self.launch_options_TRANUS()
super(OptionsTRANUSDialog, self).show()
def select_tranus_folder(self):
folder = QtGui.QFileDialog.getExistingDirectory(self, "Select directory")
if folder:
self.tranus_folder.setText(folder)
if not self.project.load_tranus_folder(folder):
self.tranus_folder.setText('')
self.reload_scenarios()
self.activate_launch_button()
I really want that the command link button should be activated when at least one element of treeview is checked and to be inactive if there is no element checked.
Thanks.
Finally, I found solution to all my problems :
def activate_launch_button(self):
model = self.scenarios.model()
model.itemChanged.connect(self.check_configure)
def check_configure(self,item):
model = self.scenarios.model()
index = model.indexFromItem(item)
if index.data(QtCore.Qt.CheckStateRole) != index.data(QtCore.Qt.UserRole + QtCore.Qt.CheckStateRole):
if index.data(QtCore.Qt.CheckStateRole)!= QtCore.Qt.Unchecked :
self.count_check+=1
model.setData(index,index.data(QtCore.Qt.CheckStateRole),QtCore.Qt.UserRole + QtCore.Qt.CheckStateRole)
else :
self.count_check-=1
model.setData(index,index.data(QtCore.Qt.CheckStateRole),QtCore.Qt.UserRole + QtCore.Qt.CheckStateRole)
print self.count_check
self.launch_btn.setEnabled(self.count_check>0)
Finally, I found a partial solution to my problem, I used the signal itemChanged http://pyqt.sourceforge.net/Docs/PyQt4/qstandarditemmodel.html#itemChanged
def activate_launch_button(self):
model = self.scenarios.model()
model.itemChanged.connect(self.check_configure)
def check_configure(self):
self.launch_btn.setEnabled(True)
It activates the button when there is one element is checked however when I uncheck all, the button doesn't become inactive. How can I solve this issue ?
I need to build a Menu using curses in python.
When user select choice, it run a function within a sub-module.
I have first a json file which contains the menu structure:
[
{
"name": "Action A",
"function": "main.foo.actionA"
},
"name": "Action B",
"function": "main.bar.actionB"
}
]
I have a main script which call the the menu.load method below:
import curses
import json
class menu:
def __init__(self):
self.curses = curses
self.screen = self.curses.initscr()
self.menuItems = json.loads(<my json menu file>)
def load(self):
x = 0
while x != ord('q'):
self.screen.addstr(2, 2, "Make your choice")
i=1
for item in self.menuItems:
self.screen.addstr(i, 4, item['name'])
i+=1
self.screen.refresh()
x = self.screen.getch()
if x == <my id item id matching the menu>:
//for example
self.run("main.bar.actionB")
def run(self, action):
function = action.split('.')
// Clear the screen, remove curse stuff so I can see intercative things in the terminal
_temp = __import__("lib.functions.%s" % function[0], globals(), locals(), [function[1]], -1)
mod = getattr(_temp, function[1])()
result = getattr(mod, function[2])()
// Once run is done, get back to menu
self.load()
This is working fine (I didn't paste all the code because there is submenu).
BUT, when user run first action first time, it works.
Then, once user is back to the menu, he can run again the same action, and then, I can see the action running twice.
If I run the same action third times, it runs three times...etc etc
I first though the importer was importing menu each times and then some kind of reference was found ... so I've tried to add control with:
try:
<run the function>
except AtributeError:
//function is not loaded, load it
But it didn't work..
I am developing a demo program based on PyGobject that has parts in its interface like stocks management that should refresh every few seconds. The program has the need to be able to run 24/7 while keeping the displayed information correct.
I have a container which has its content in stacks(and separately there are tabs to change between them):
def main_content(self):
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
self.stack = Gtk.Stack()
self.stack.get_style_context().add_class("main-container")
self.stack.props.margin = 20
self.child1_child = self.child1()
self.child1_child.set_visible(True)
self.stack.add_named(self.child1_child, "Child1")
self.child2_child = self.child2()
self.child2_child.set_visible(True)
self.stack.add_named(self.child2_child, "Child2")
self.child3_child = self.child2()
self.child3_child.set_visible(True)
self.stack.add_named(self.child3_child, "Child3")
box.pack_start(self.stack, True, True, 0)
if self.redraw:
print("Redrawing")
self.redraw = True
return box
So, there are functions to generate each stack member, they are assigned to variables, and then set as visible and added to the stack.
Lets suppose that the stack Child1 has a list of stocks, and i don't want it to have more than 5 minutes of delay. I tried to do a redraw function where a list is making the tabs, and this redraw function is either evoked by a timeout_add or a tab click :
def redraw(self):
selected_stack = self.listbox.get_selected_row().get_index()
# **Possible** solution:
stack_elements = {0: "Child1", 1: "Child2", 2: "Child3"}
variables = {0: "child1_child", 1: "child2_child", 2: "stock_child"}
self.variables[janela].destroy()
self.variables[janela] = self.stack_elements[janela].lower()
self.variables[janela].set_visible(True)
self.stack.add_named(self.variables[janela], stack_elements[janela])
# Problems: Doesn't works as python code. Just an idea
# **Possible** solution 2:
self.stack.destroy()
self.stack = Gtk.Stack()
self.stack_content = self.main_content()
self.main_box.pack_start(self.stack_content, True, True, 0)
These were just some try-error ideas, i never made an interface with the need to be kept updated, is there any proper way to do so, or a way to make one of my ways work?
I have a GUI that has 4 widgets which are user inputs (file in/out and directory in/out). I am trying to make a button that will do two things.
I want to button when clicked to send the four user set parameters to another imported function.
self.btn.clicked.connect(lambda: self.sendData(self.rawName, self.outName, self.directoryIn, self.directoryOut))
I was using something like this. Where send data looks like this:
def sendData(self, rawName, outName, directoryIn, directoryOut):
try:
foo.main(rawName, outName, directoryIn, directoryOut)
except TypeError:
pass
In this case foo.main is the imported function. The user input method looks like this:
def setInputDirectory(self):
options = QtGui.QFileDialog.DontResolveSymlinks | QtGui.QFileDialog.ShowDirsOnly
directoryIn = QtGui.QFileDialog.getExistingDirectory(self,
"Some Directory",
self.directoryLabelIn.text(), options)
if directoryIn:
self.directoryLabelIn.setText(directoryIn)
Finally, I want to have the button (btn) be clickable only when all four values are entered in the gui.
self.rawName = ""
self.outName = ""
self.directoryIn = ""
self.directoryOut = ""
...
self.btn.clicked.connect(self.sendData)
self.btn.setEnabled(False) # disable button here, enable it later
so you can simply send those parameters directly:
def sendData(self):
try:
foo.main(self.rawName, self.outName, self.directoryIn, self.directoryOut)
except TypeError:
pass
also after every input, check if all four values are entered and if so enable button:
def areAllFourValuesEntered(self):
if (self.rawName!="" and self.outName!="" and self.directoryIn!="" and self.directoryOut!=""):
self.btn.setEnabled(True)
I have 15 def's. I have 15 radiobuttons (p1,p2,p3.....p15). I have 1 QPush Button.
When i want to use my first def, i select "p1" click on my QPushButton and then use this def. Why i need it? because i need process texts, i open a text into my textedit and i need process it, but i want to use only one def using radiobutton.
How can i do it?
for example:
self.radioButton_1 = QRadioButton(self.Processing)
self.radioButton_1.setGeometry(QRect(520, 200, 50, 22))
self.radioButton_1.setObjectName(_fromUtf8("radioButton_1"))
self.radioButton_1.setText(QApplication.translate("Form", "P1", None, QApplication.UnicodeUTF8))
self.processLineButton = QPushButton(self.Processing)
self.processLineButton.setGeometry(QRect(800, 100, 100, 37))
self.processLineButton.setText(QApplication.translate("None","Process", None, QApplication.UnicodeUTF8))
and
def example(exampless):
example = []
for exx in exampless:
es = re.findall("\.{3}!", exx)
if es:
example = example + [exx]
#endif
#endfor
self.TextProcess.setPlainText(example)
First you'll need to find the checked radio button, then you can run the function assigned to that button, something like this:
for radioButton in self.findChildren(QtGui.QRadioButton):
if radioButton.isChecked():
radioButtonText = radioButton.text()
print "Radio Button Selected: ", radioButtonText
if radioButtonText == "example":
example(args)