AlwaysOnTop property not behaving properly - x++

For some reason, the AlwaysOnTop attribute for a form's design isn't properly working.
Here's the context: we are trying to have a form that stays on top of every other one when opened. Simple no? Also, we don't want to set the WindowType to Popup according to my superior for some other reason (if you have any idea why, please let me know).
So my question is, is there any parameter/security feature somewhere that somehow restricts the forms to be on top at any time?
Even WinApi's setForegroundWindow returns false with the form's hWnd. Any ideas?
Oh, also we're running on Dynamics AX 4.0.

If you want your form to have modal behavior, then call the wait method from the form itself!
public void run()
{
super();
this.wait(true);
}
The true parameter triggers the modal mode. This works on all versions of AX.
The wait may be called from the caller instead, but that is less attractive as most forms are called through menu items.
formRun.init();
formRun.run();
formRun.wait(true);

I managed this case long time ago with the lostFocus event and the setFocus method. I didn't find a proper way to make a form stay on top (I think AX prevents this specifically to avoid locking a terminal) but it worked fine this way: When the form lost focus, set the focus on the form.
I don't have the code as it was on an old project. It was for a PDA project but I think you can't ever avoid user on changing form with Alt+Tab.
This is an interesting point, please keep us updated.
EDIT:
Someome in twitter got an cute solution for modal forms. I'm pretty sure it will make the trick for you. In the init method of the form:
public void run()
{
super();
element.wait(true);
// Execution will resume at this point, only after
// the user has closed the form.
}
Source: http://gotdax.blogspot.com.es/2013/08/modal-forms-in-dynamics-ax.html

What I did to solve this was by making the form modal through WinAPI. The code below is a copy from a saved text so it might need some polishing. (Also keep in mind that it might not be working as of AX2009.)
void setFormModal(int _thisHWND, boolean _bModal)
{
DLL _winApiDLL;
DLLFunction _EnabledWindow;
DLLFunction _getTop;
DLLFunction _getNext;
DLLFunction _getParent;
void local_enableWHND(int _lHWND)
{
int lnextWnd;
lnextWnd = _getTop.call(_getParent.call(_lHWND));
while (lnextWnd)
{
if (lnextWnd != _lHWND)
_enabledWindow.call(lnextWnd, (!_bModal));
lnextWnd = _getNext.call(lnextWnd, 2);
}
}
;
_winApiDLL = new DLL('user32');
_getNext = new DLLFunction(_winApiDLL, "GetWindow");
_EnabledWindow = new DLLFunction(_winApiDLL, "EnableWindow");
_getTop = new DLLFunction(_winApiDLL, "GetTopWindow");
_getParent = new DLLFunction(_winApiDLL, "GetParent");
_getParent.returns(ExtTypes:: DWORD);
_getParent.arg(ExtTypes:: DWORD);
_EnabledWindow.returns(ExtTypes:: DWORD);
_EnabledWindow.arg(ExtTypes:: DWORD, ExtTypes:: DWORD);
_getTop.returns(ExtTypes:: DWORD);
_getTop.arg(ExtTypes:: DWORD);
_getNext.returns(ExtTypes:: DWORD);
_getNext.arg(ExtTypes:: DWORD, ExtTypes:: DWORD);
local_enableWHND(_thisHWND);
local_enableWHND(_getParent.call(_thisHWND));
}

Related

TabControl - How to force event OnGetImageIndex

I have a Delphi VCL form application (for Windows) with a TabControl component, where tabs are created at run time. Images property is linked to a ImageList, and I am using the OnGetImageIndex event to set the image index for each tab, based on a status information. At certain point, when status change, I need to update this images (indexes). My first idea is to call:
TabControl1.Invalidate;
But it doesn't work. I also tried another approachs without success:
TabControl1.Repaint;
RedrawWindow(TabControl1.Handle, nil, 0, RDW_ERASE or
RDW_INVALIDATE or RDW_ALLCHILDREN);
Please, how can I force OnGetImageIndex for each tab? Thanks!
You can call the protected UpdateTabImages method which sends a TCM_SETITEM for each tab.
type
TAccessTabControl = class(TTabControl);
...
TAccessTabControl(TabControl1).UpdateTabImages;

Getting multiple button captions into an edit field with one fuction

I want to create a function which takes the Caption of a pressed button and put it into an Edit field. I have multiple buttons, and I don't want to have multiple OnClick events with almost the same code in each of them.
I've searched and tried out stuff for hours, but can't seem to find anything like that (but I think I am not the only one with this problem).
I am not really new to programming but neither am I good at it.
Edit: I remember that there is a parameter in the click functions in .NET which is EventArgs e, which is missing while working with Embarcadero.
private void button_Click(object sender, EventArgs e)
{
edit.Text = e.Caption; //I don't really remember the exact syntax but I hope you get what I meant
}
Most VCL/FMX event handlers have a Sender parameter, which is a pointer to the object that is firing the event. For example:
void __fastcall TMyForm::ButtonClick(TObject *Sender)
{
Edit1->Text = static_cast<TButton*>(Sender)->Caption;
}
Just assign this single event handler to the OnClick event of all of your TButton objects. The Sender will be the current button being pressed.
Note to the above answer by Remy - for VCL the property name is "Caption" but for FMX the property name for a button is "Text"

Getting selected ListBox values on button Click | ZK

I am very new to ZK framework and trying to customize few things and have struck at one point which I am not sure how to achieve that.
I have a predefined section where I need to show 2 drop down and a button and need to persist those drop down values on button click event.
This is how It has been define in Spring file
<bean id="mybean" parent="parentBean" class="WidgetRenderer">
<property name="detailRenderer">
<bean class="DetailsListRenderer" parent="abstractWidgetDetailRenderer"/>
</property>
</bean>
Here mybean is being used to show main section and I am adding my drop down using this bean while button are being added to detailRenderer.
Save button is bind to onClick event, but I am not sure how I can fetch values from my custom drop down?
I am aware about binding those Dropdown with onClick event but they have to be in same class.
Can any one suggest me how I can fetch values of those drop down.I am creating down down with following code
Listbox listbox = new Listbox();
listbox.appendItem("item1", "item1");
listbox.appendItem("item2", "item2");
This is my button code in another class
protected void createUpdateStatusButton(Widget widget,Div container)
{
Button button = new Button(LabelUtils.getLabel(widget, buttonLabelName, new Object[0]));
button.setParent(container);
button.addEventListener("onClick", new EventListener()
{
public void onEvent(Event event)throws Exception
{
MyClass.this.handleSaveStatusEvent(widget, event);
}
});
}
You may want to listen to the onSelect (I prefer to use Events.ON_SELECT rather than writing the strings) which is more specific to when the Listbox selection changes.
Either way, the key is to get the information you want from the Event passed to your EventListener, rather than going back to your Listbox itself. The basic Event usually carries useful information on getTarget and getData but using more specific events (SelectEvent in this case) will give you access to more relevant info.
button.addEventListener(Events.ON_SELECT, new EventListener<SelectEvent<Listitem, MyDataObject>() {
public void onEvent(SelectEvent<Listitem, MyDataObject> event) {
// Now you can access the details of the selection event..
List<Listitem> selectedItems = event.getSelectedItems();
List<MyDataObject> selectedObjects = event.getSelectedObjects();
}
});
You can find out what events are available for different ZK widgets in their Component Reference documentation.
If I understand the question (I don't think I did in my previous response) you want to gather information from the page (eg: Listbox selection state) when the user clicks a button. Your problem being that you are using disparate classes to compose the page and so don't have access to the various ZK Components when the button is clicked.
(Ignoring the multiple class issue for a minute)
From a high level, there are sort of two camps in the ZK community. The newer MVVM approach suggests the view should push the relevant state to the back end as the user interacts with the front end. This way, the back end never needs to ask for the client state, and when the button is clicked, the values/state are on the server ready to be used.
The other camp binds the client to the server such that the back end always has access to the client Components and when the button is clicked, the values/state can easily be retrieved by interacting with the components.
Another approach is more like what I was talking about in my previous answer, to not bind the back end to the client at all but to rely on event data as much as possible. I favor this approach where it is sufficient.
Now, you're free to choose your favored approach and ZK has lots of documentation on how to work in either of these camps. The question then is where is the client state stored on the server (either pushed there by the client in MVVM or bound there in MVC). I don't think that's a question that can be solved here, that's a software engineering challenge. I personally suggest you take on standard ZK patterns so as not to but heads with the framework. If you really want to go your route, you can grab a reference to the Listbox on the fly like so:
public class Foo {
public static final String LISTBOX_ID = "myListbox";
public void renderListbox(Component parent, MyItem items) {
Listbox listbox = new Listbox();
listbox.setId(LISTBOX_ID);
listbox.setParent(parent);
for (MyItem item : items) {
listbox.appendItem(item.getName(), item);
}
}
}
public class Bar {
#Listen(Events.ON_CLICK + " = #saveButton")
public void saveButtonClicked(Event event) {
Component saveButton = event.getTarget();
Listbox listbox = (Listbox) saveButton.getFellow(Foo.LISTBOX_ID);
Set<Listitem> selection = listbox.getSelectedItems();
// do something
}

Why isn't the keydown event firing?

I'm trying to attach an event handler to the keyDown event in a canvas element. Here is a simplified version of my code.
class CanvasFun{
CanvasElement canvas;
CanvasFun(this.canvas){
print("Game is loading!");
this.canvas.onKeyDown.listen(handleInput);
}
void handleInput(e)
{
//breakpoint is never hit
print(e.keyCode);
}
}
I've removed some of the drawing code. In my main function I simply query the canvas element and pass it to my CanvasFun constructor.
I've also tried doing it this way:
void main() {
var canvas = query("#Game");
canvas.onKeyDown.listen(handleInput);
var canvasFun = new CanvasFun(canvas);
}
void handleInput(e)
{
print(e.keyCode);
}
The reason why the event is not firing is because the focus is on the document (or some other element like an input, for example). And in fact, canvas element even when focused does not fire an event. Some elements do, like input elements.
The solution is to listen to key down events from the document or window:
window.onKeyDown.listen(handleInput);
document.onKeyDown.listen(handleInput); // You already noticed this worked.
John McCutchan has written a nice Dart package to help handle keyboard input. You can read more about it here: http://dartgamedevs.org/blog/2012/12/11/keyboard-input/
Note that this library helps you handle input "correctly". You do not want to do any "work" in the input handling, instead you simply want to register that a key was pressed. You can check the state of any key presses inside of your requestAnimationFrame callback.
Hope that helps!
There exists a workaround to get the canvas-element accept KeyboardEvents:
Problems handling KeyboardEvents on DartFlash
Once you add the tabindex-attribute to your canvas-element, it can get the focus and then it will receive KeyboardEvents.
It looks like I can get it to work if I register the event on the document rather than the canvas element.
document.onKeyDown.listen(handleInput);

What windows messages are used by Delphi to notice changes in a combo box?

I have a Delphi application A, which I need to control from a .NET application B.
Among other things, I need to automate this process:
User selects item X from a combo box.
Application A notices the change and reacts by displaying a certain panel.
This works fine, if I do it manually.
But when the application B selects a combo box value, no panel is displayed.
This is the problem.
Potential cause of it:
When I select a combo box item, a certain windows message is fired. Some Delphi routine reacts to this message.
When I select a combo box item programmatically, the only message I send is CB_SETCURSEL and the Delphi app seems to ignore it.
Hence I assume that I can fix the problem, if I
get to know what windows messages are used as a basis for notification about combo box value changes (e. g. OnChange) and
send that windows message from C# application.
Therefore my question: What are the windows messages, on whose occurrence OnChange (and other events that notify the Delphi application on changed combo box selection) are fired?
Update 1: Started to implement the solution proposed by David Heffernan
private const int CB_SETCURSEL = 0x14E;
private const int WM_COMMAND = 0x0111;
private const int CBN_SELCHANGE = 0x001;
private const int CN_COMMAND = 0xBD11;
private int MakeWParam(int l, int h)
{
return (l & 0xFFFF) | (h << 16);
}
...
IntPtr comboBoxHandle = new IntPtr(comboBox.Current.NativeWindowHandle);
SendMessage(comboBoxHandle, CB_SETCURSEL, (Int32)myIndexInComboBox, 0);
SendMessage(comboBoxHandle, CN_COMMAND, MakeWParam(0, CBN_SELCHANGE), 0);
At the moment, it doesn't work.
Update 2:
I noticed a very strange thing.
If I invoke CB_SETCURSEL only, the desired item is selected in the combo box.
If I invoke CB_SETCURSEL and then (after 5 seconds) CN_COMMAND, then nothing is selected in the combo box.
This means - CB_SECURSEL selects the item and CN_COMMAND undoes it.
Update 3: Styles of the combo box according to Spy++:
WS_CHILDWINDOW
WS_VISIBLE
WS_CLIPSIBLINGS
00000243
Extended styles:
WS_EX_LEFT
WS_EX_LTRREADING
WS_EX_RIGHTSCROLLBAR
Class styles:
CS_VREDRAW
CS_HREDRAW
CS_DBLCLKS
Update 4: When I select the combo box item manually, I see following messages in the Spy++ output:
<00177> 0195085E S message:0xBD33 [Custom:WM_APP+15667] wParam:6801164A lParam:0195085E
<00178> 0195085E R message:0xBD33 [Custom:WM_APP+15667] lResult:4610165A
Unfortunately, I couldn't find documentation for this message.
Update 5: I noticed that the reaction to combo box selection change does occur, but only after a relatively long time (30 seconds to 1 minute). When I do the same thing manually, the reaction occurs instantaneously.
Potential cause of this behaviour: The thread of the .NET application makes the thread of the Delphi application wait for it. Note that the UI interaction code in the .NET app is executed in a separate thread (not the UI thread).
You should follow the CB_SETCURSEL message by sending the combo box a WM_COMMAND message with NotifyCode equal to CBN_SELCHANGE. It's the CBN_SELCHANGE that triggers the OnChange event.
In Delphi the code would look like this:
SendMessage(ComboHandle, CB_SETCURSEL, NewSelectionIndex, 0);
SendMessage(ComboHandle, WM_COMMAND, MakeWParam(0, CBN_SELCHANGE), ComboHandle);
Or you could use the CN_COMMAND message instead which would perhaps be a little more direct:
SendMessage(ComboHandle, CB_SETCURSEL, NewSelectionIndex, 0);
SendMessage(ComboHandle, CN_COMMAND, MakeWParam(0, CBN_SELCHANGE), 0);
You'll want to translate that into whichever .net language you are using, but I'm sure that's easy for you.
When the user selects a ComboBox item by hand, the control receives a CBN_SELCHANGE notification, which then triggers the TComboBox.OnChange event. When you select a ComboBox item programmably, no CBN_SELCHANGE notification is sent. This is documented behavior:
http://msdn.microsoft.com/en-us/library/windows/desktop/bb775821.aspx
The CBN_SELCHANGE notification code is not sent when the current selection is set using the CB_SETCURSEL message.

Resources