I am creating an application, where "Left Arrow + Down Arrow" press has different behavior ( It is not same as first left arrow and then left arrow ), currently in keyPressEvent event I am getting them one by one in two separate calls.
Is there any way by which I can get multiple keypress in one keyboard event?
Thanks for this. I am posting code for the Python (PyQt) equivalent so that someone else might find it useful.
def keyPressEvent(self, event):
self.firstrelease = True
astr = "pressed: " + str(event.key())
self.keylist.append(astr)
def keyReleaseEvent(self, event):
if self.firstrelease == True:
self.processmultikeys(self.keylist)
self.firstrelease = False
del self.keylist[-1]
def processmultikeys(self,keyspressed):
print keyspressed
I solved the problem by below code.
QSet<Qt::Key> keysPressed;
void Widget::keyPressEvent(QKeyEvent * event) {
m_bFirstRelease = true;
keysPressed+= event->key();
}
void Widget::keyReleaseEvent(QKeyEvent *) {
if(m_bFirstRelease) {
processMultiKeys(keysPressed);
}
m_bFirstRelease = false;
keysPressed-= event->key();
}
Nothing is "at the same time" and I believe in Qt you can't have that type of behaviour (except for modifier keys like shift, alt, etc).
Approach the problem in a different way. When you receive one of the keys, check to see if you received the other in a short while back, say 20ms before.
Related
I'm using go-qt bindings (therecipe).
I faced such a problem that I cannot bring the window with the file dialog forward, I tried all the functions (and their combinations) that I could find on the Internet, but none of them did not help bring the dialog up.
I try to use this function:
fileDialog.SetWindowFlag(core.Qt__WindowStaysOnTopHint,true)
fileDialog.ActivateWindow()
fileDialog.SetWindowState(core.Qt__WindowActive)
fileDialog.SetWindowState(core.Qt__WindowMinimized|core.Qt__WindowActive)
fileDialog.Raise()
fileDialog.SetFocus2()
I also noticed a feature that if you call the dialog again after fileDialog.Exec (), then it will be displayed on top of all windows as needed.
code for this case
var fileDialog = widgets.NewQFileDialog2(nil, "Open Directory", "", "")
if fileDialog.Exec() != int(widgets.QDialog__Accepted) {
return
}
if fileDialog.Exec() != int(widgets.QDialog__Accepted) {
return
}
Code for function where I'm using Dialog:
func choseFile(){
var fileDialog = widgets.NewQFileDialog2(nil, "Open Directory", "", "")
fileDialog.SetAcceptMode(widgets.QFileDialog__AcceptOpen)
fileDialog.SetFileMode(widgets.QFileDialog__ExistingFile)
fileDialog.SetWindowFlag(core.Qt__WindowStaysOnTopHint,true)
if fileDialog.Exec() != int(widgets.QDialog__Accepted) {
return
}
fmt.Println(fileDialog.SelectedFiles()[0])
}
Problem might be related to native dialogs (in my case I am using ubuntu), so I put the flag DontUseNativeDialog. Then the problem was solved.
filename := widgets.QFileDialog_GetOpenFileName(ac.MainWindow,"Open Directory","","","",widgets.QFileDialog__DontUseNativeDialog)
upd: Its works even if the first argument is nil.
When I have a dialog and multiple buttons have the same click-callback (action method) I mostly want to know which button has been pressed. How do I do that?
Example:
class ButtonDialog : UIFrame{
void button_pressed(object self){
// how do I get this button
TagGroup pressed_button = ?;
result("The button " + pressed_button + " is pressed.\n");
}
object init(object self){
TagGroup dlg, dlg_items, button1, button2;
dlg = DLGCreateDialog("Press a button", dlg_items);
button1 = DLGCreatePushButton("Button 1", "button_pressed");
button1.DLGIdentifier("button1");
dlg_items.DLGAddElement(button1);
button2 = DLGCreatePushButton("Button 2", "button_pressed");
button2.DLGIdentifier("button2");
dlg_items.DLGAddElement(button2);
self.super.init(dlg);
return self;
}
}
object dialog = alloc(ButtonDialog).init();
dialog.pose();
In my current program I have multiple rows created from a TagGroup. Each row has multiple buttons doing the same thing but for their specific row. Therefore I need to know which button it is to get the row to modify. Also the length of the TagGroup and therefore the row count is not fixed. So I cannot create button1_pressed, button2_pressed, ... functions except with doing some weird stuff with code evaluation on the fly which I want to avoid if possible.
The fact that you cannot pass an argument in the simple call-back of a push-button is a bit of a bummer. The easiest solution (albeit not elegant) is to use simple-one-line-callback methods which are unique but themselves call a generalized method as in the code below.
Of course mile7 stated that the number of buttons isn't fixed at compile time, which is an issue here. But unless the (potential) number of buttons is legion, this approach is still the easiest and cleanest, and as each "hard coded" call-back is only one line with a very systemic change, it should be fairly trivial to use Notepad++ or similar to provide an extensive enough set of such calls. (It doesn't hurt if some of them are actually never used.)
class ButtonDialog : UIFrame{
void button_pressed(object self, string buttonID){
// how do I get this button
TagGroup pressed_button = self.LookUpElement(buttonID);
if ( pressed_button.TagGroupIsValid() )
result("The button " + buttonID + " is pressed.\n");
else
result("The button " + buttonID + " was not found!\n");
}
// Need to be done for each button
void button_pressed_0(object self) { self.button_pressed("button0"); }
void button_pressed_1(object self) { self.button_pressed("button1"); }
object init(object self){
TagGroup dlg, dlg_items
dlg = DLGCreateDialog("Press a button", dlg_items);
number nButtons = 2
for( number n=0; n<nButtons; n++ ){
TagGroup button = DLGCreatePushButton("Button " + n , "button_pressed_" + n);
button.DLGIdentifier("button" + n);
dlg_items.DLGAddElement(button);
}
self.super.init(dlg);
return self;
}
}
object dialog = alloc(ButtonDialog).init();
dialog.pose();
So I kind of found an answer which I can live with, but I'm still hoping for better results.
My current idea is to use DualStateBevelButtons. If a button gets clicked, the state changes and the callback is executed. Then all buttons are checked if they have a changed state. If so, this is the clicked button and the state is reset.
The very very big downside of this solution is, that there are only buttons with images allowed, no text is possible. So this is not really the general solution to work with.
rgbimage button_img = RGBImage("button-image", 4, 16, 16);
button_img = max(0, 255 - iradius / 8 * 255);
class ButtonDialog : UIFrame{
TagGroup buttons;
void button_pressed(object self){
for(number i = 0; i < buttons.TagGroupCountTags(); i++){
TagGroup button;
if(buttons.TagGroupGetIndexedTagAsTagGroup(i, button)){
if(button.DLGGetValue() == 1){
// this button is toggled so it is clicked
string identifier;
button.DLGGetIdentifier(identifier);
result("Button " + i + " (" + identifier + ") is clicked.\n");
// reset button state
button.DLGBevelButtonOn(0);
// do not continue searching, found pressed button already
break;
}
}
}
}
object init(object self){
TagGroup dlg, dlg_items, button1, button2;
dlg = DLGCreateDialog("Press a button", dlg_items);
buttons = NewTagList();
button1 = DLGCreateDualStateBevelButton("button1", button_img, button_img, "button_pressed");
buttons.TagGroupInsertTagAsTagGroup(infinity(), button1);
dlg_items.DLGAddElement(button1);
button2 = DLGCreateDualStateBevelButton("button2", button_img, button_img, "button_pressed");
buttons.TagGroupInsertTagAsTagGroup(infinity(), button2);
dlg_items.DLGAddElement(button2);
self.super.init(dlg);
return self;
}
}
object dialog = alloc(ButtonDialog).init();
dialog.pose();
After adding logic about creating price for object in grid it's always created "one line more" which is empty.
So, if there is need to be created two lines, it will be created 3 lines and that one addition will be empty.
Is there something what I missing in code?
[Control("CommandButton")]
class AreaActionPaneNew
{
void clicked()
{
PMCParameters contractParameters = PMCParameters::find();
PMETmpRentalObjectArea groupedAreaList; // Group by area_type and cost_type
PMERentalObjectPrice priceList;
date workingDate = currWorkingDate.dateValue();
;
super();
// Get grouped area values. Values are summed up by area_type and ancost_type
groupedAreaList = PMERentalObjectAreaCl::getRentalAreaPrCostType(pmeRentalobject.RentalObjectId, userSetting.validFrom(), userSetting.validTo() , workingDate);
ttsbegin;
while select groupedAreaList
{
select forupdate firstonly priceList
where priceList.RentalObjectId == pmeRentalObject.RentalObjectId &&
priceList.RentalCostType == groupedAreaList.RentalCostTypeId &&
priceList.AreaType == groupedAreaList.Areatype && priceList.ValidFrom == pmeRentalObject.ValidFrom;
if (!priceList)
priceList.initValue();
priceList.RentalObjectId = pmeRentalObject.RentalObjectId;
priceList.RentalCostType = groupedAreaList.RentalCostTypeId;
priceList.ValidFrom = pmeRentalobject.ValidFrom;
priceList.AreaType = groupedAreaList.Areatype;
priceList.Amount = groupedAreaList.Price;
priceList.Area = groupedAreaList.AreaValue;
priceList.Quantity = groupedAreaList.RentalQty;
if (!priceList)
priceList.Period = contractParameters.ReportPeriod;
if (priceList)
priceList.update();
else
priceList.insert();
}
ttscommit;
pmeRentalObjectPrice_ds.research();
}
}
The code looks like it only updates/inserts without creating a blank line.
From your attribute, you are using a Command Button (see here), which may have an associated command, such as New, which effectively pushes Ctrl+N, and would explain why you have a blank line.
The simplest way to check is just create a regular Button and override the clicked method, then copy/paste your code and push both buttons and see if they have different behavior.
Check the Command property on the button and see if there's something there. Try commenting out the super(); call.
You should perhaps consider just a Button or a Menu Item Button with an associated object.
in Flex I have something like that:
var dg:DataGrid = new DataGrid();
if (something) dg = dg1 else if (something_2) dg = dg2;
dg.dataProvider.getItemAt(3).id;
and dg is ALWAYS pointing at DataGrid (even if dg1 has name DataGrid_test and dg2 = DataGrid_test2) and finally action is made on my first DataGrid (DataGrid_test).
Why?
How can I pass dg1 or dg2 to dg?
Here is pasted almost full code of this part of application. I edited it to make that more clear.
var dg:DataGrid = null;
if ( currentState == "state1" ) { //if this condition is true then app. go into if and
dg = dataGrid_first; // make dg = DataGrid (1)
test.text = "inco"; // shows "inco" in "test" label
} else if ( currentState == "state2" ) { // if this is true then app. go..
dg = dataGrid_second; //here and set dg as DataGrid (exactly!) (2)
test.text = "outgo"; // and change test label into blank text (earlier text disapears)
}
search(dg);
It is modified with advice of '#splash'
Still not working.
EDIT:
I made this sceond edit to answer for all You who are helping me with that :) I think that it will be the best way. In codeblock above I added comments. (please read now comments and after that come back here :) )
Now I will explain exactly what happens.
I debug it many times and here are results:
dg is pointing at DataGrid (as component in flex, not as my dataGrid_first), I needed to extend DataGrid so now it is ColorColumn component (I don't know if I called it properly), not DataGrid. And dg is pointing at ColorColumn not at dataGrid_first or dataGrid_second. I even tried today the same thing what suggest #splash:
if ( currentState == "state1" ) {
test.text = "inco";
search(dataGrid_first);
} else if ( currentState == "state2" ) {
test.text = "outgo";
search(dataGrid_second);
}
and search still points at ColorColumn :/ My problem is really easy- I just want to pass to search different dataGrid on each state. If You have other ideas how I can do that in right way then I will pleased to hear about it. :)
But still I don't understand why it doesn't work. My search function uses algorhitm Boyer-Moor for searching through dataGrid.dataProvider for some text. If it find something then it is pushed into new array and after passing whole dataProvider I colorize rows with searched word.
If dg is never pointing to dg1 and dg2 then your (something) expressions may be evaluate to false. Check the value of your if-conditions - this should be easy to debug.
This should work:
var dg:DataGrid = null;
if (something)
dg = dg1;
else if (something_2)
dg = dg2;
if (dg)
{
// do something with dg
}
[Update]
I still can't see why your code isn't working, but you could simplify it like this:
if ( currentState == "state1" ) {
test.text = "inco";
search(dataGrid_first);
} else if ( currentState == "state2" ) {
test.text = "outgo";
search(dataGrid_second);
}
I'd propose to write this - since I guess either dg1 or dg2 should be assigned:
if (something) {
dg = dg1;
} else {
dg = dg2;
}
There may be cases, where if () {} else () {} neither executes the first or the second conditional block.
Finally a small hint, which structurally eliminates unwanted assignments in if conditions: Always write the literal left of the comparison operation: if ( "state1" == currentState ). If you accidentally typed = instead of ==, the flex compiler emits an error. The other notation silently assigns a value.
Additionally: Did you single-stepped through your code and watched the variables dg1, dg2 and dg? If not, set a breakpoint a few line before the if-statement and run the code step by step from there on. What do you see?
Here's a another tip: Use assertions to check for inconistencies:
package my.company.utilities {
public function assert(expression:Boolean):void {
// probably conditionally compile this statement
if (!expression) {
throw new Error("Assertion failed!");
}
} // assert
}
Use it e.g. at the beginning of a method like this:
public function doTransaction( fromAccount:int, toAccount:int ) {
assert( 0 < fromAccount );
assert( 0 < toAccount );
}
A typically good use of assert is to check variables regarding their range. As of the above example, fromAccount and toAccount should always be positive. Due to a bug, bad values might get passed to doTransaction(). In this case, the assertion fires an error.
I have a switch statement in my action script class.I have a function onKeyDown(event: KeyboardEvent) which contain a switch statement.which control the different keys.
But now I want to handle the same functionality which TAB key is doing using two keys CTRL and SPACE key.
I want add a case more in my switch statement first I pressed CTRL and then SPACE key then a a specific function is called.
Anyone can tell me how two keys used in my switch statement?
private function onKeyDown(event: KeyboardEvent) : void{
if (popUp.displayPopUp){
switch (event.keyCode){
case Keyboard.UP:
case Keyboard.DOWN:
case Keyboard.END:
case Keyboard.HOME:
case Keyboard.PAGE_UP:
case Keyboard.PAGE_DOWN:
inputTxt.selectRange(text.length, text.length)
list.dispatchEvent(event)
break;
case Keyboard.ENTER:
acceptCompletion();
break;
case Keyboard.TAB:
if (requireSelection)
acceptCompletion();
else
popUp.displayPopUp = false
break;
case Keyboard.ESCAPE:
popUp.displayPopUp = false
break;
case Keyboard.CONTROL && Keyboard.SPACE:
if (requireSelection)
acceptCompletion();
else
popUp.displayPopUp = false
break;
}
}
}
This is a pretty common problem.
event.keyCode is only going to give you the keyCode for the most recent key pressed. So you will have to store key presses and key releases. Fortunately, AS3 is a pretty sweet Array implementation that allows this to be done easily.
var _keys:Array;
addEventListener(KeyboardEvent.KEY_DOWN, keyDownEvent);
addEventListener(KeyboardEvent.KEY_UP, keyUpEvent);
function keyDownEvent(e:KeyboardEvent)
{
// turn the key on
_keys[e.keyCode] = true;
// perform logic
keyLogic()
}
function keyUpEvent(e:KeyboardEvent)
{
// turn the key off
_keys[e.keyCode] = false;
}
function keyLogic()
{
// this is where the actual logic is
if(_keys[Keyboard.SPACE] && _keys[Keyboard.CONTROL])
{
if (requireSelection)
acceptCompletion();
else
popUp.displayPopUp = false
}
}
This allows you to have a neat little array that always tells you what keys are down. It also separates your program logic from your input logic. Double win.
In your case you can just check ctrlKey property on KeyboardEvent. But #DingoEatingFuzz's answer will allow check combinations like 'space' + 'letter' and so on.
case Keyboard.SPACE:
if (event.ctrlKey)
{
}
break;
i think this one approch is good........