I wrote a little tool in Lazarus to use it as a launcher for some games of mine, all of this is done by cmd scripts which are linked to the press of a button.
Now I'm looking for two modifications to my tool, but since I'm not very talented when it comes to programming, I hope somebody can help me.
The first thing I'm looking for is to split the TButton caption into two lines. I have tried to do it over the GUI but did not find a solution for this.
The second thing I want to do is to change the caption and the function of a button by pressing on it. For example Button1 has the caption Enable Enhancements, which runs the script enhancements_on.bat. After I press the button, I want it to change the caption to Disable Enhancements, in order that the script enhancements_off.bat will run on next press.
Is this possible? if yes, how do you do it?
I've find out. In case anyone needs a feature like this, use a togglebox and the following code:
procedure TForm1.ToggleBox1Change(Sender: TObject);
begin
if ToggleBox1.Checked then
begin
ToggleBox1.Caption:='Mods aktiviert.'
ShellExecute(0,nil, PChar('cmd'),PChar('/c "start enhancements_on.bat"'),nil,1)
end
else ToggleBox1.Caption:='Mods deaktiviert.';
ShellExecute(0,nil, PChar('cmd'),PChar('/c "start enhancements_off.bat"'),nil,1)
end;
The first thing I'm looking for is to split the TButton caption into two lines.
Simply set the caption of the Togglebox at runtime, e.g. in the OnCreate event of the form and use LineEnding to split the lines.
Togglebox1.Caption := 'Line 1' + LineEnding + 'Line 2';
Note that this works only with TTogglebox, not with TButton.
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.
UPDATE3 - SOLVED with reservations, please see my solution below; leaving it open since the cause of the problem is unclear, and I don't know how robust the solution is.
UPDATE1: here's the short short version.
Currently, after .setEditText on a QComboBox, I get this:
so the next thing you type will overwrite 'Team '.
But the desired effect is this (unhighlighted / unselected), so that the next thing you type will be appended to 'Team ' instead of overwriting it:
Thanks for any help. The rambling details are below, which is the original post:
(this is all PyQt 5.4)
UPDATE2:
Apparently python doesn't think anything is actually selected:
self.entryForm.ui.teamField.lineEdit().setText("Team ")
print("selected text:"+self.entryForm.ui.teamField.lineEdit().selectedText())
prints "selected text:" and nothing else. To make sure that's working:
self.entryForm.ui.teamField.lineEdit().setText("Team ")
self.entryForm.ui.teamField.lineEdit().setSelection(0,4)
print("selected text:"+self.entryForm.ui.teamField.lineEdit().selectedText())
prints "selected text:Team"
So that might be why many of the methods that affect selection are not working as expected (.deselect(), .setSelection(5,5), etc, and even some of the other methods give unexpected behavior, i.e. cursorForward(False,1) or cursorBackward(False,1) and such.
Original post:
This is for a radio log GUI, so keyboard interactions must be minimal and intuitive. openNewEntryForm (below) is called as a slot from a pushbutton on the main application GUI window:
self.ui.pushButton.clicked.connect(self.openNewEntryDialog)
It can also be called using a keyPressEvent in the same class:
def keyPressEvent(self,event):
if type(event)==QKeyEvent:
print("QKeyEvent:"+str(event.key()))
if event.key()==Qt.Key_T:
self.openNewEntryDialog('t')
event.accept()
else:
event.ignore()
Here's the method in question:
def openNewEntryDialog(self,key=None):
self.entryDialog=newEntryDialog()
if key=='t':
self.entryDialog.ui.to_fromField.setCurrentIndex(1)
self.entryDialog.ui.teamField.setFocus()
self.entryDialog.ui.teamField.setEditText("Team ")
if self.entryDialog.exec_():
self.newEntry(self.entryDialog.getValues()) # adds the log entry
so, the intended key press sequence is (from the main application GUI window):
a single keyboard press of 't' will open the entryForm, set the to_fromField to index 1 (which happens to be "TO"), give focus to teamField (also a QComboBox), set its text to "Team " and set itself up so that the very next keypress will appear as the text following "Team " in teamField.
So, starting from the main app GUI again, the plan is that typing 't3' should open the new entry window, set the to_fromField to "TO", and set the teamField to "Team 3", ready for a keypress of the tab key to move on to the next field in the entryForm.
The problem is that the teamField.setEditText("Team ") call leaves all of the text highlighted/selected, so that a subsequent key press of '3' would replace "Team " with "3"; I'm looking for a way to unhighlight/unselect "Team " but leave the cursor active at the right of that string, so that the subsequent key press of '3' would make the entire string "Team 3".
Ideas? Thanks in advance.
You can access the line-edit of the combo box, and then remove the selection:
self.entryDialog.ui.teamField.setEditText("Team ")
self.entryDialog.ui.teamField.lineEdit().deselect()
UPDATE:
The above code is correct, but it seems that the dialog will then clobber it when it initialises the focus handling for its child widgets after it is shown. If a dialog is opened with exec(), it will start its own event-loop, and some events (including focus events) will only be processed after it is fully shown. This is why it may appear that some changes made to child widgets before the dialog is shown are being ignored.
One way to work around this is to use a single-shot timer to ensure the changes are only attempted after the dialog is shown.
So add a method to the entry dialog class something like this:
def resetUI(self, key):
if key == 't':
self.ui.to_fromField.setCurrentIndex(1)
self.ui.teamField.setFocus()
self.ui.teamField.setEditText('Team ')
QtCore.QTimer.singleShot(0, self.ui.teamField.lineEdit().deselect)
and then use it like this:
def openNewEntryDialog(self, key=None):
self.entryDialog = newEntryDialog()
self.entryDialog.resetUI(key)
if self.entryDialog.exec_():
self.newEntry(self.entryDialog.getValues())
SOLVED with reservations, see UPDATE3 in the original post.
So, with the initial text all highlighted, tests show that it didn't actually think anything was selected. This solution was just stumbled upon by trial and error, fiddling with setting and clearing focus, selecting text and trying deselect:
def openNewEntryDialog(self,key=None):
self.entryForm=newEntryDialog()
if key=='t':
self.entryForm.ui.to_fromField.setCurrentIndex(1)
self.entryForm.ui.teamField.lineEdit().setFocus()
self.entryForm.ui.teamField.lineEdit().setText("Team ")
self.entryForm.ui.teamField.lineEdit().setSelection(5,1)
Notice there are two spaces after 'Team' and the second one is intentionally selected. Then the very next keypress will overwrite that second space; that is basically the desired behavior.
Anyway it looks like something bizarro with the selection scheme; one way to look at this is that the highlight isn't really a selection, but, if you set a valid real selection then it will override the original highlighted 'pseudo-selection'. The original highlighting behaves like a selection in that a keypress will replace everything that's highlighted, but, not like a selection in that the selection methods reveal that there is no 'selection', see UPDATE2 in the original post.
Can anyone help explain this behavior? I'd like to build some more confidence in it before accepting this coincidental answer.
Thanks
I have problem with button's caption in VB6.
I'm trying to change caption after "_load" event and it works, but new text is not in the center of the button - and it's a problem.
You can see it on the following screen:
https://dl.dropboxusercontent.com/u/3779161/buttons.png
I've tried to use "Refresh" function but without any effect.
Is it possible to refresh button without creating new one?
Thanks for help
I am unable to test VB6 code currently but, apparently, it requires Win-API calls to align the text. code here. Copy the code into a Module and then you can call the function AlignCommandButtonText. (Seems like hard work!)
the new text does center for me.
run the following test project and click on the form:
'1 form with
' 1 commandbutton: name=Command1 caption="Test"
Option Explicit
Private Sub Form_Click()
Command1.Caption = "New Test"
End Sub
the problem is probably caused by something else.
for example: do you have any tight loops?
could you post some of your code?
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.
Take a look at the top-right of the Stack Overflow site. The search box has some text in it saying "search". When you click within it, the text disappears.
I want to do something similar to this - if a win32 edit control is empty (i.e. has no text), I want to paint some text inside it, in a more subdued color than the normal text. If the control has the focus, or if there's text inside it, I don't want to paint that.
Is there any way I can do it without setting the actual text into the control and changing the text color? Maybe by intercepting the control paint or something?
Thanks.
It is possible as of XP. Check the EM_SETCUEBANNER message. However, there are certain issues that make it not work entirely as it should on XP, so it's best if you're dealing with Vista.
If you need it for Win2k or older versions, you'll need to do it yourself, at least on those platforms.
Thanks for this question, I will be able to use this in the future.
FWIW (not much, probably), here is an implementation in Delphi:
procedure TForm1.FormShow(Sender: TObject);
const
ECM_FIRST = $1500;
EM_SETCUEBANNER = ECM_FIRST + 1;
begin
SendMessage(edt.Handle,EM_SETCUEBANNER,0,LParam(PWideChar(WideString('Enter search here'))));
end;
One possibility: Make it owner-draw, and manually paint the text onto it if the .Text property is empty.
Take a look at EM_SETCUEBANNER
Maybe, but why not just set the default text and color as needed, and clear it with an 'onClick' event?
You don't need owner-drawn, it's native with User apis (Banner)
See Winapi grp for samples (in C)