I have the following code and it correctly shows the InvoicingUnit on the message box. It also shows the value in the caption correctly.
ADItemRecord := GetInvItemRecord(txtItemCode.Text);
ShowMessage(ADItemRecord.InvoicingUnit );
lblUnit.Caption := ADItemRecord.InvoicingUni;
But the following change (i.e., removing the Message box), shows no caption. The caption is blank.
ADItemRecord := GetInvItemRecord(txtItemCode.Text);
lblUnit.Caption := ADItemRecord.InvoicingUni;
I believe this is to do with the program moving on to the next line before the data is ready in the record. So I did the following change hoping that the program will correctly complete the fetch and then move on.
ADItemRecord := GetInvItemRecord(txtItemCode.Text); //Fetch data from DB
Application.ProcessMessages; //Wait for it to complete (I think)
lblUnit.Caption := ADItemRecord.InvoicingUnit;
Application.ProcessMessages;
But the above change has no effect.
Am I correct to assume that calling Application.ProcessMessages will wait till the previous line correctly completes?
The function GetInvItemRecord is meant to fetch the record from the DB.
The program is built on Ubuntu with Postgres.
Application.ProcessMessages signals that the app can execute events from its event queue. Let's say that you have 2 buttons on a form with to onclick procedures assigned. The first procedure is a lengthly process (eg. repeat ... until true). The second button has only ShowMessage('haha').
Now, without appllication.processmessages inserted in the first procedure in the repeat statement, if you press the first button then you will not be able to press the seccond button (or anything else) until the repeat statement finishes. So the user interface is frozen.
With the application.processmessages inserted like
repeat
Application.ProcessMessages;
...
until true;
if you press the first button and then the second button the showmessage will happen! So, it is a way to fake a multithread app :-))
I hope that i was clear.
This was one of the difficult ones since I did not know what to look for. I've included my answer here so that someone else may also benefit from this.
I thought perhaps it was not the problem (delay) in calling the function to fetch data, but an issue with delayed screen painting or refreshing. Then I found these two links:
What's the difference between Refresh, Update and Repaint?
and this:
http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/Controls_TControl_Update.html
So I decided to call the Update procedure after assigning the value to the caption. That was the solution to my problem.
I still am not sure how Application.ProcessMessages works - smiles.
Related
I have a fairly large program, and I need a way to suppress all the Windows beeps you get on pressing enter. I found a function that allows me to suppress all beep sounds, but I need the error sounds to be fired when something goes wrong, so that is not an option. I saw you could suppress the sound for a single textbox by setting the Key to 0, but this is not an option as there are a LOT of keypress events in my program.
You can suppress these beeps that are produced when an edit control has the focus and you press ESCAPE and ENTER by setting TForm.KeyPreview to True and then adding the following OnKeyPress event handler for your form:
procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
if (Key=#13) or (Key=#27) then
Key := #0;
end;
If you have some controls for which you wish to accept ENTER or ESCAPE, for instance multi-line edit controls, then you could leave KeyPreview as False, and handle OnKeyPress for each single-line edit control:
procedure TForm1.EditKeyPress(Sender: TObject; var Key: Char);
begin
if (Key=#13) or (Key=#27) then
Key := #0;
end;
Or you could leave KeyPreview as True and then have a form-wide OnKeyPress handler that discriminated based on the control that has the focus. For example, a rather crude example:
function IsSingleLineEdit(Edit: TCustomEdit): Boolean;
var
Style: DWORD;
begin
Style := GetWindowLongPtr(Edit.Handle, GWL_STYLE);
Result := Style and ES_MULTILINE = 0;
end;
procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
if (ActiveControl is TCustomEdit)
and IsSingleLineEdit(TCustomEdit(ActiveControl)) then
if (Key=#13) or (Key=#27) then
Key := #0;
end;
However, I would suggest that you do none of these things. I suggest that you leave the behaviour as it currently is. If neither the form, nor the focused control is going to response to these key presses, then beeping is the most appropriate response. The user presses ESCAPE when she wants to cancel the current dialog. If you are not going to respond to that, then the system beeps to indicate that. Likewise, the user presses ENTER when she wants to accept the current dialog. Again, since your dialog doesn't respond, a beep is appropriate.
I saw you could surpress the sound for a single textbox by setting the Key to 0, but this is not an option as there are a LOT of keypress events in my program. Is there any solution to this?
This is actually the correct approach to do this provided that specific EditBox does have proper code to execute certain action upon pressing the Enter key.
If you don't have any specific code to process some action on pressing the Enter key when in certain field then the Ding sound should be heard to tell the user he is doing something wrong.
Same would go if you are limited specific EditBoxes to only numbers. So that every time when the user presses any letter key the Ding sound is played and the user knows that letters are not allowed. Othervise the user might thing that there is something wrong with his keyboard.
You wouldn't want to be a guy who made a software whose usage resulted in lots of keyboards getting busted. Or would you? :-)
So I'm afraid you would have to do lots of code editing for a lot of KeyPress events. I must admit that I kinda feel sorry for you. Been in similar position once.
As for David Heffernan suggestion about filtering the Enter and Escape keys using forms KeyPreview.
Don't! Realy! DON'T! Why?
Becouse by doing so you could interfeere with normal functionality of some other components.
For instance using that code with combination of ComboBox prevents you from using Escape key to colapse the expanded combo box.
If I have a ButtonClick event which sets Cursor := crHourglass, Application.ProcessMessages, then use a TOpenDialog to choose a file, and then do something CPU-intensive, the cursor behaves differently depending on whether it is over the existing control when the Open Dialog closes. If the cursor is over the control then the cursor remains as an hourglass; if it's outside the application completely and then moved into the area while the intensive process is still taking place, the cursor remains as an arrow. One cannot click or do anything so it's confusing to the user to get an arrow but not be able to do anything with it.
Stepping through the debugger shows the Cursor is -11 everywhere it should be. Using Screen.Cursor instead of Cursor has the same effect.
Is there a solution?
procedure TMyForm.LoadButtonClick(Sender: TObject);
begin
Cursor := crHourglass;
Application.ProcessMessages;
if OpenDialog.Execute then begin
// Do something intensive
// Cursor = crHourglass here but what is displayed is different
end;
Cursor := crDefault;
end;
First, make sure to set the cursor only while the CPU-intensive operation is active. Don't change the cursor while choosing a file — you never see any other programs do that, after all.
Second, when you say Cursor in your code, you're referring to the form's property. You might wish to use Screen.Cursor instead so that your entire program displays the same cursor.
Third, there's no need to call Application.ProcessMessages. Messages are going to be processed as soon as you display a dialog box anyway, and besides, there are no particular messages you need processed.
Finally, consider protecting the cursor changes with a try-finally block so that problems in your processing don't leave the cursor in the wrong state:
if OpenDialog.Execute then begin
Screen.Cursor := crHourglass;
try
// TODO: something intensive
finally
Screen.Cursor := crDefault;
end;
end;
If the operation really uses a lot of time, consider moving it off to another thread. Then you don't have to worry about the GUI being unresponsive, and so you won't have to change the cursor in the first place.
I'm new to ApplescriptObjC as you'll probably see if you keep reading. I was wondering how to get constant feedback from a slider so that as soon as its value is 1 it runs script A and as soon as its value is changed to 0, it runs script B.
I know you can have actions for buttons like:
on buttonClicked_(sender)
do action
end buttonClicked_
But how can I have a one that constantly checks for a change in the slider's value and does the appropriate action? Is it similar to connecting a slider to a text box with the getStringValueFrom() thing?
Any help would be appreciated. Thanks :)
Found out how!
turns out on action_(sender) will work for sliders as well. They send the signal every time the item is clicked on and released whether a change exists or not. Then its a simple matter of an if statement to run two different series of actions depending on the value the slider was set to.
I created an application with two forms. First one is the main form and second one is hidden.
I placed a button on Form1 and I made it ShowModal the second form. On Win7 the form appears with an animation. Then I close the appeared form (Form2) and I click the button once again. Form2 appears without the animation. I want the animation every time. What should I do?
The only thing I can think of right now is to create the form manually each time you want to display it modally. To do this, go to the project options and make sure that the form isn't automatically created. Then do
procedure TForm1.Button1Click(Sender: TObject);
begin
with TForm2.Create(self) do
try
ShowModal;
finally
Free;
end;
end;
In my opinion, most often modal forms should in fact be created manually.
Well, you could just elect not to worry about it! Alternatively a very quick hack would be to free the form each time it closes since the animation appears to run only on the first time the form is shown.
EDIT: Another approach would be to call DestroyHandle on your form whenever it closes. I'm guessing now, but I imagine that Windows records somewhere in the window a flag indicating that the animation has been shown. Once this flag has been set the animation is never shown again.
As an alternative way it's possible to fool windows by sending a notification that form's style has been changed, that will make windows reset "secret flag" for current form's handle. Thus, on showing already created form the cool show effect animation will be applied again. However, I can't say what negative effects can be caused by doing this way.
uses
Winapi.Windows, Vcl.Controls;
type
TFormHelper = class helper for TForm
public
procedure Show;
end;
implementation
procedure TFormHelper.Show;
begin
SendMessage(Handle,CM_CUSTOMSTYLECHANGED,0,0);
inherited Show;
end;
Note: code featured with a class helper, this feature/keyword might be not available in older IDEs.
It's a longshot that anyone can help with this, but here goes. I inherited a VB6 app with a Janus GridEX control. It iterates through records, and is editable. Problem is, if I edit a cell and hit the button to go to the next record, the change is applied to the next record, not the one I was editing. It's like, I need it to finish up the edit before going to the next record. I've had this sort of problem before in VC++, and sometimes you have to "KillFocus" on the control you're on or something. I just don't know what to do here. I tried sending a carriage return, since if you return out of the edit cell, it works, but sending a carriage return manually doesn't work. What's the secret?
Is your grid bound or unbound?
It's hard to tell from your description, but I imagine that if your are having this problem then it's probably bound.
As the other answer asked, is the button the RecordNavigator that is built into the control or is it a separate button? The reason I bring this up again, is that I have seen issues in the VB6 applications I support where a toolbar will often intercept and interfere with how the JanusGrid should work.
To get around this limitation, I have added the following code in the click handler of any toolbars where there is also a JanusGrid control on the form.
If jsgxYourGridName.EditMode = jgexEditModeOn Then jsgxYourGridName.Update
This way any changes are immediately applied to the current row.
If this does not help, then I have also seen problems where the recordset that is bound to the grid gets out of sync with the internal recordset in the grid. You can check this by comparing the bookmark of the grid to the bookmark of the recordset.
Ie. mrsYourRecordset.Bookmark = jsgxYourGrid.ADORecordset.Bookmark
At one point I may have also used something like this.
jsgxYourGrid.ADORecordset.Bookmark = jsgxYourGrid.RowBookmark(jsgxYourGrid.RowIndex(jsgxYourGrid.Row))
Finally you can try setting a breakpoint in the BeforeUpdate, RowColChange and/or AfterColUpdate events of the grid, to see what record the grid is really on when clicking on the button.
It depends whether the button is internal to Janus GridEX or not. If it internal then just about the only thing you can do is look at the events the control exposes to see if there a sequence that can let you know that this problem occurs. Then you can try to take corrective action by restoring the row you moved to and put the edit in the row you left.
If the button is external to Janus then you can use the debug mode to trace sequence of statement that control the transfer of focus to the next row. It could be something out of order or a side effect of the particular sequence of commands. I have run into both with different controls.
Remember that you can edit while in debug mode so you can try different approaches and test until you find one that works.