Just getting started with PyGTK and Glade3 and would love some help.
Container Hierarchy:
window -> vbox1 -> {button1 , label1}
button1 calls back to
on_button1_clicked(self, widget):
print "Hello World!" #This sends the output to the console
widget.set_label("Hello World!") #This updates button1's label
#I'd like to update label1's label as well in the same callback
I know this can be done using label1.set_text(string), but I don't know how to retrieve that object any ideas?
Thanks from KY.
label = builder.get_object('label1')
label.set_text('foobar')
Related
I have a modal with two buttons, one Accept and one Cancel.
I set the cancel button to be the default with .setDefault() and .setAutoDefault()
Pressing return activates the cancel-button, but when I press spacebar the accept-button is activated.
Why is the application/accept-button ignoring the defaultness-configuration and activates on spacebar presses rather than the cancel button? It seems like the accept-button has focus or something despite there being a different default.
Why would the default not have focus?
If I call cancel_button.setFocus() just before showing the modal (but not earlier than that), even the spacebar will activate the Cancel-button instead of the Acccept-button, so that solves the underlying problem.
The question is why spacebar and enter do not both activate the default button.
Minimal example:
The modal shows up when the program is run, as well as when the user presses X.
Press ctrl+Q to close the application.
import sys
from PyQt5.QtCore import QSize, Qt
from PyQt5.QtGui import QKeySequence
from PyQt5.QtWidgets import QApplication, QMainWindow, QGroupBox, QHBoxLayout, QVBoxLayout, \
QWidget, QShortcut, QDialog, QPushButton
class Modal(QDialog):
def __init__(self, parent):
super().__init__(parent)
self.resize(QSize(600, 300))
self.setParent(parent)
self.setWindowModality(True)
layout = QVBoxLayout()
self.setLayout(layout)
buttons = self.create_buttons()
layout.addWidget(buttons)
# This sets focus (when pressing spacebar), and makes the modal work as expected.
# The question is why is this needed to make spacebar default to activating Cancel?
# Why is spacebar activating Accept by default without this line?:
#self.cancel_button.setFocus()
def create_buttons(self):
button_groupbox = QGroupBox()
button_box_layout = QHBoxLayout()
button_groupbox.setLayout(button_box_layout)
# Despite setting the defaultness, pressing spacebar still activates the accept-button.
# Pressing return activates the cancel-button, however, and is expected behaviour.
# Why is the Accept-button being activated when space is pressed?
accept_button = QPushButton("Accept")
accept_button.clicked.connect(self.accept)
accept_button.setDefault(False)
accept_button.setAutoDefault(False)
self.accept_button = accept_button
cancel_button = QPushButton("Cancel")
cancel_button.clicked.connect(self.reject)
cancel_button.setDefault(True)
cancel_button.setAutoDefault(True)
self.cancel_button = cancel_button
# This does not set focus (when pressing spacebar), maybe because it has not been added yet?
#cancel_button.setFocus()
button_box_layout.addWidget(accept_button)
button_box_layout.addWidget(cancel_button)
return button_groupbox
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
shortcut = QShortcut(QKeySequence("Ctrl+Q"), self)
shortcut.activated.connect(app.quit)
shortcut = QShortcut(QKeySequence("X"), self)
shortcut.activated.connect(self.run_modal)
self.resize(QSize(800, 600))
self.show()
def showEvent(self, event):
self.run_modal()
def run_modal(self):
self.modal = Modal(self)
self.modal.finished.connect(self.modal_finished)
self.modal.show()
def modal_finished(self, result):
if result == 0:
print("CANCEL")
elif result == 1:
print("ACCEPT")
else:
raise Exception("BAD RESULT")
if __name__ == '__main__':
app = QApplication(sys.argv)
mainwindow = MainWindow()
sys.exit(app.exec_())
By default, widgets receive focus based on the order in which they are added to a parent. When the top level window is shown, the first widget that accepts focus, following the order above, will receive input focus, meaning that any keyboard event will be sent to that widget first.
Note that when widgets are added to a layout, but were not created with the parent used for that layout, then the order follows that of the layout insertion.
The default property of QPushButtons, instead will "press" the button whenever the top level widget receives the Return or Enter keys are pressed, no matter of the current focused widget, and as long as the focused widget does not handle those keys.
In your case, the currently focused widget is the "Accept" button (since it's the first that has been added to the window), which results in the counter-intuitive behavior you're seeing.
If you want the cancel button to react to both Return/Enter keys (no matter what is the focused widget) and the space bar upon showing, then you have to explicitly call setFocus(). But there's a catch: since setFocus() sets the focus on a widget in the active window, it can only work as long as that widget already belongs to that window.
In your case, the cancel_button.setFocus() call done within create_buttons won't work because, at that point, the button doesn't belong to the top level window yet.
It does work when you do that after layout.addWidget(buttons), because then the button is part of the window.
So, considering the above:
if you want to set the focus on a widget, that widget must already belong to the top level widget before calling setFocus();
the default button will always be triggered upon Return/Enter keypress even if another button has focus;
With your current code, you either do what you already found out (using setFocus() on the instance attribute after adding the widget), or use a basic QTimer in the create_buttons function:
QTimer.singleShot(0, cancel_button.setFocus)
Note that:
while creating separate functions can help you to better organize your code, having a separate function that is just called once is often unnecessary (other than misleading and forcing the creation of instance attributes where they're not actually necessary); just separate code blocks with empty lines, unless those functions can be overridden by further subclasses;
setting a "Cancel" button that can be activated by Return/Enter is not a very good idea, as those keys are generally used for "Accept/Apply/Commit/Write/etc." purposes;
if you want to show a dialog as soon as its parent is shown, you shall only use a QTimer: QTimer.singleShot(0, self.run_modal); the paint event is certainly not a viable option (paint events occur very, very often, and in some systems even when the widget loses focus, which can cause recursion), nor is the showEvent() since that could happen when switching virtual desktops or unminimizing the window;
I want to increase the value of i every time the button is clicked
I've tried this code but it's not working.
val textview = findViewById<TextView>(R.id.texttest)
var i = 10
bookbutton.setOnClickListener {
i++
}
textview.text = "$i"
You have to set the text inside the listener:
bookbutton.setOnClickListener {
i++
textview.text = "$i"
}
Your listener is updating the value of i — but that's not having any visible effect because by then it's too late: the text shown in your textview has already been set.
Let's review the order of events:
Your code runs. That creates a text view and a variable, sets a listener on the button, and sets the text in the text view.
At some later point(s), the user might click on the button. That calls the listener, which updates the variable.
So while your code sets the listener, the listener does not run until later. It might not run at all, or it might run many times, depending on what the user does, but it won't run before you set the text in the text view.
So you need some way to update the text when you update the variable. The simplest way is to do explicitly it in the listener, e.g.:
bookbutton.setOnClickListener {
textview.text = "${++i}"
}
(There are other ways — for example, some UI frameworks provide ways to ‘bind’ variables to screen fields so that this sort of update happens automatically. But they tend to be a lot more complex; there's nothing wrong with the simple solution.)
I can close the virtualkeyboard from a button by calling textField.stopEditing. However, I would have expecting setting a DoneListener to close the virtualkeyboard as well when "Search" or "Go" is pressed.
The DoneListener does fire and the code is executed, but the virtualkeyboard remains open. I've tried adding a stopEditing to the DoneListerer, even placing stopEditing callSerially.
I just tried this on my Android OPO device and it worked as expected. The second field did nothing but the first folded the keyboard like a champ:
Form hi = new Form("TextTest", BoxLayout.y());
TextField other = new TextField("");
TextField ttt = new TextField("");
hi.add(ttt).add(other);
ttt.setDoneListener(e -> {
hi.add(ttt.getText());
hi.getContentPane().animateLayout(200);
});
hi.show();
How to make a simple entry dialog box (like in the image) in blender and processing the text entered through python.I am unable to find any good tutorial on this.
For the dialog box the answer from how to show a message from a blender script? might be a starting point.
But I think a better approach is integrating input into the panel like e.g.
To do this you have to add a StringProperty to your add-on and place it inside your panel (see Addon Tutorial for more information). The basic steps are:
def draw(self, context) :
col = self.layout.column(align = True)
col.prop(context.scene, "my_string_prop")
...
def register() :
bpy.types.Scene.my_string_prop = bpy.props.StringProperty \
(
name = "My String",
description = "My description",
default = "default"
)
...
def unregister() :
del bpy.types.Scene.my_string_prop
...
You can access the string by context.scene.my_string_prop
There is another mode to integrate input. When you add for example a text to your scene you can change the parameters after the operator has been called and see the changes immediately:
Changing Location will move the newly created text object at another place. I haven't worked with this but it should be similar to the code above.
actually this should be a pretty simple question, but I am experiencing the quite steep learning curve of chaco and traits...
I am currently writing an application to plot a medical image using chaco and traits and I simply want to pick a pixel location from the image and use this pixel location to do evaluations on an image stack. So I started to write my own Chaco Tool that reacts on mouse clicks on an imageplot.
This works fine so far. When I click on the imageplot I can see the mouse coordinates WITHIN the Tool (a custom made PixelPickerTool). However, as I want to use this coordinate value outside the tool my question would be: How can I hand the coordinates over to another object or variable OUTSIDE the Tool when an event is fired.
To illustrate what I want to do I attached the main structure of the two classes I am Writing:
class PixelPickerTool(BaseTool):
'''Pick a Pixel coordinate from an image'''
ImageCoordinates = [0,0]
def normal_left_down(self, event):
print "Mouse:", event.x, event.y,
click_x, click_y = self.component.map_data((event.x, event.y))
img_x = int(click_x)
img_y = int(click_y)
coord = [img_x, img_y]
if ( (img_x > self.ImageSizeX) or (img_x < 0) ):
coord = [0,0]
if ( (img_y > self.ImageSizeY) or (img_y < 0) ):
coord = [0,0]
print coord
# this print gives out the coordinates of the pixel that was clicked - this works fine...
# so inside the picker too I can get the coordinates
# but how can I use the coordinates outside this tool ?
class ImagePlot(HasTraits):
# create simple chaco plot of 2D numpy image array, with a simple interactor (PixelPickerTool)
plot = Instance(Plot)
string = String("hallo")
picker = Instance(PixelPickerTool)
traits_view = View(
Item('plot', editor=ComponentEditor(), show_label=False,width=500, height=500, resizable=False),
Item('string', show_label=False, springy=True, width=300, height=20, resizable=False),
title="")
def __init__(self, numpyImage):
super(ImagePlot, self).__init__()
npImage = np.flipud(np.transpose(numpyImage))
plotdata = ArrayPlotData(imagedata = npImage)
plot = Plot(plotdata)
plot.img_plot("imagedata", colormap=gray)
self.plot = plot
# Bild Nullpunkt ist oben links!
self.plot.default_origin = 'top left'
pixelPicker = PixelPickerTool(plot)
self.picker = pixelPicker
plot.tools.append(pixelPicker)
I want to use the coordinates that are measured by the PixelPickerTool somewhere in this ImagePlot class. E.g. by handing them over to another Object like MyImageSeries.setCoordinate(xy_coordinateFromPickerTool)
So how can I hand over the pixel coordinates from PickerTool to some member variable in this class when an event is fired ?
Maybe something like this: self.PixelCoordinates = picker.getPixelCoordinates() could work ?
But how do I know then, when the on_normal_left_down function was executed in the picker ?
In the end I want to hand the coordinates over to another class which hold more images to process the images and do a fit at the pixel position determined in the ImagePlot.
I tried to use something like "_picker_changed" in my imagePlot class to detect if an event has been fired in the PickerTool, but this didn't detect event firing. So maybe I am doing something wrong...
Can anybody tell me how to get events and associated variables out of this picker tool ?
Cheers,
Andre
"But how do I know then, when the on_normal_left_down function was executed in the picker?"
There are several ways you could probably do this, but one way would be to simply do exactly what you are asking and fire an event that you define explicitly.
for instance:
from traits.api import Event
class PickerTool(BaseTool):
last_coords = SomeTrait
i_fired = Event
def normal_left_down(self,event):
# do whatever necessary processing
self.last_coords = do_some_stuff(event.some_attribute)
# now notify your parent
self.i_fired = True
and then listen to plot.picker.i_fired from wherever you want to display, and look in plot.picker.last_coords for the saved state.
Another thing you can do that may be simpler if what you want to do with these coordinates is very straightforward, is just pass on intialization the data structures the picker needs to interact with (or get them with a chain of calls to self.parent) and do your work directly inside the picker.