Related
It may sound silly, but I encountered a few situations, when I would like the application not to show what is happening, until an another specific action happens (stringGrids are filled with data, UI is prepared...). Is there a way to prevent messages from being sent from application to OS?
So, is there some oposit to
application.processmessages
?
Something like:
application.stopProcessingMessages;
fill stringGrids, prepare the UI...
application.processMessagesAgain;
?
Of course, I could run the actions in a separate thread, but there are situations where I either don't want to, or cannot do it in a separate thread.
Check TDataSet.DisableControls for data aware controls, and BeginUpdate / EndUpdate for some VCL / RTL classes (including TStrings), and - specific for the mentioned TStringGrid - see Delphi TStringGrid Flicker
It turned out, that although I thought, that using the WM_SETREDRAW message is the right solution, it has a few disadvantages. The biggest one is, that if used, user can click through the form. So the final solution is simply an empty TPanel placed over the whole form like this
panel1.Left:= 0;
panel1.Top:= 0;
panel1.Width:= frmMain.Width;
panel1.Height:= frmMain.Height;
After the form is prepared, the panel is shrunk, made invisible etc. It reliably hides every flickering and other things, that doesn't look good, and I want to hide them from the user.
I have an application which is designed for multiple monitors. It starts up, and we try to avoid activating windows that do not need to be activated, because the user only does keyboard input in one place, and each time we Activate a new form on a secondary monitor, it grabs keyboard focus, something we wish to avoid.
Our in-house base TForm class has a method like this, which is using the Win32 ShowWindow function directly, avoiding the VCL framework's internal visibility change system which grabs focus:
procedure TOurForm.ShowWithoutActivate;
begin
ShowWindow(Self.Handle, SW_SHOWNOACTIVATE);
Self.Visible := true;
end;
If I just did this, it would grab focus:
Self.Visible := true; // TWindow.Visible = true, will grab focus, plus make window visible.
This works, but the next thing I'd like to be able to do is set Maximized state so that the
form will maximize itself on the Monitor that it is currently on. How do we get it onto a particular monitor? The same way it always worked, with modification of the Left and Top properties of the Form. We have to take care that if we store Left/Top/Width/Height on form, and then restore it, that the results are still valid when we reload it. That is NOT what I'm asking about.
I'm specifically asking about how to maximize the form now that I have "showed" it using the above custom function. One hack begets another hack. Here is how far down this rabbit hole I've gone:
When a TForm, which is also a TWinControl's private field FShowing is false, setting Form.Maximized has no effect.
When a TForm has its TWinControl.FShowing field set true, setting the windowState to wsMaximized also causes the form to activate.
Is it possible to both make this form visible and make it take the window state I want it to take without activating? If I can't do this, then users are going to lose their keyboard focus when I show this form on a secondary monitor, something that I really want to avoid.
What I tried is to use Win32 ShowWindow API to do SW_SHOWMAXIMIZED:
ShowWindow(Self.Handle, SW_SHOWMAXIMIZED);
The above seems to grab focus (activate).
When you create the top-level window set the extended window style to
WS_EX_NOACTIVATE | WS_EX_APPWINDOW
WS_EX_NOACTIVATE stops the window activating. This also makes it disappear from the taskbar, so you need WS_EX_APPWINDOW to fix that problem.
Call ShowWindow(hWnd, SW_MAXIMIZE) and the window will be maximized but not activated.
You need to be able to activate the window once it is visible, so in the WM_ACTIVATE handler (the irony!) you need to clear the WS_EX_NOACTIVATE flag thus:
case WM_ACTIVATE:
{
DWORD exstyle = GetWindowLong(hWnd, GWL_EXSTYLE);
if (exstyle & WS_EX_NOACTIVATE)
{
SetWindowLong(hWnd, GWL_EXSTYLE, exstyle & ~(DWORD)WS_EX_NOACTIVATE);
}
}
Apologies for the C++. This should be simple to translate into Delphi.
EnumDisplayMonitors API enumerates the monitors and their coordinates on the joint desktop, area into which a particular monitor maps to its specific position.
To find out which monitor is "current" you would want to compare the current window position against monitor coordinates rcMonitor/rcWork. Or, you have MonitorFromPoint and friends to help you.
Once to decided which monitor you want, you can either move your window (MoveWindow, SetWindowPos) to monitor's work area, or use this rectangle in response to WM_GETMINMAXINFO message to send the window to this position as a part of standard maximization.
To add to this, this small C++ application [1, 2, 3] demos the concept mentioned above, shows monitor information, and changes position where the window would be maximized to.
I am looking for a alternative to Raize components' tab control.
I would like to have the ability to add close button at the top of each page and I want to use slanted tabs and colors on the tabs. Oh, and I'm using FireMonkey 2.
//I know that raize does not support firmonkey.
Firemonkey has it's own TTabControl in the Common Controls page (by default). You can style this using a TStylebook. For example, I'm quite confident it's possible to add a close button onto the tab itself.
After all, FMX is a vector-based framework and so all visual elements must exist within the style. You'll probably want to load a style into a TStylebook for this, as I'm unable to find a way to load the default style into one. Navigate down to tabitemstyle, and from there you'll be able to tweak the visual appearance of it. Simply add a close button as you'd like (alignment, layout, etc).
Back in your application code, you'll be looking to use the FindStyleResource routine in order to setup the code (XE2 uses FindBinding and as such you'd set the BindingName property instead). I'm going to assume your close button is called 'CloseButton' (without the quotes);
var
MyTab : TTabItem;
begin
MyTab := ((TabItem1 as TTabItem).FindStyleResource('CloseButton') as TButton).OnClick := TabClose;
end;
You'd want to add that code when you initially create the tab, or if creating all the tabs at design time, you'll want to run it at FormCreate. You're basically telling it that when CloseButton is clicked, that you want to call the notify event/procedure TabClose. This procedure is identical to a button click.
You could go so far as changing the StyleName property of the tab to be CloseButton+Index_of_tab.
Now, as for the code to close the tab itself, something like this untested example may work, though you'll want to iterate on it.
procedure TForm1.TabClose(Sender: TObject);
var
_mytab : Integer;
_activetab : Integer;
begin
_activetab := ((Sender as TTabItem).Parent as TTabControl).ActiveTab.Index;
_mytab := ((Sender as TTabItem).Parent as TTabControl).ActiveTab.Index;
((Sender as TTabItem).Parent as TTabControl).Tabs[_MyTab].Free;
((Sender as TTabItem).Parent as TTabControl).TabIndex := _activetab;
end;
Now, this is the clever part, and exploits the design of the framework. When you click on a style element that's inside another element, by default, it'll select the parent element. In this example, it'll select the tab that contains the close button the user clicked on. From this, it'll then close that tab (technically, it'll free it, I've not dealt with tabs much in development so you'll want to look into the proper method of 'closing' them).
There is one problem with this though; You'll probably want to find a better way of detecting the previously active tab if you wish to switch back to it. Right now, it'll simply open the tab that was after the tab you just closed (since the tabcount is now 1 less, the active tab index selects the next physical tab). You'll probably be able to do this by splitting the _activetab code off elsewhere.
I've done similar things with some of my own programs, and this is how I usually create 'hybrid' components. You're essentially exploiting the modular design of the framework to make it do what you want it to do, without having to rely on third party components.
Since FMX is a pretty young framework there aren't many 3rd party component vendors that support it yet.
I haven't seen any 3rd party TabControl component for FMX and a quick Google search suggests there aren't any. So you might be out of luck.
I know this is an old query but in case anyone is still looking for tabs with close buttons and slanted tab sides, check out TMSSoftware's TTMSFMXTabSet. I'm using it in a current development project and it is working fine.
i know that windowless controls are not magic. A windowless control can have input focus (e.g. Internet Explorer). Input focus is nothing more than drawing either:
a blinking cursor
a dotted line around the perimeter
a slight blue tinge on a button
and when the user begins mashing keys, reacting appropriately. You know the keystrokes are meant for that focused control, because that's the control has focus.
In the case of my (Windows®) window, i would have to know that my windowless child control (let's pretend it's a descendant of TGraphicControl) gets the keyboard events. So during my form's OnKeyDown, OnChar, OnKeyUp, i would need to pretend they are going to my windowless child control.
Which i can do, but it is a pain.
But then the user will probably want to use Tab navigation, and i'll have to somehow intercept Delphi's normal tab control order handling, and hook in myself to say that this thing is the next (and previous) in the tab order.
Which i can do, but it is a pain.
And then there's ActiveControl, which doesn't understand anything except TWinControl's. So if Delphi ever tries to figure out who has focus, it will go insane. So i'd have to have an alternate implementation of ActiveControl.
Which i can do, but it is a pain.
In other words: is this just too much work? i'm fighting eveything that Delphi is, all so i can have a few dozen windowless controls accessible through keyboard input? The Delphi designers never contemplated using interactive windowless controls, and if i try now to work it in, i'll just stuck in the hurtlocker?
Delphi gave me the chance of aiding me willingly, but i have elected the way of pain.
Some further explanation of windowless controls is needed.
Not every control you interact with has to be a windows control. It is quite possible to have focus on, and send keyboard input to, a control that is not a Windows window.
For example, nearly every control you see in an Internet Explorer browser window is a windowless control. In the following screenshot you can see an edit control, which you can type in, and a button which (in this screenshot) has focus:
You can see the dotted focus rectangle, and the button is bluish (which on Windows indicates that it has focus).
If i were to press Spacebar while the Google Search button has focus, it would press the button. The reason this works is because Microsoft wrote an entire widget library of controls. These controls look and feel (almost) exactly like the regular common controls - they are very nearly exact clones of the Windows common controls, right down to the themes being applied.
Mozilla Firefox and Google Chrome also use a widget library of controls. They don't use Microsoft's built-in windowed controls, but instead use a library of graphical, interactive, windowless widgets.
And if you have a suitable development environment, then the windowless widgets work just like "normal" windowed controls. GTK+ is a widget library, and Glade is an IDE that lets you layout controls in that widget library.
i don't know in what development environment Firefox, Chrome, or Blender were created in, but their widgets support windowless controls.
So now onto my question.
Unless i'm mistaken, it appears to me that although Delphi supports a base TControl, (which has width, height, and can paint itself), it cannot receive keyboard focus. It seems to me that Borland never designed Delphi's VCL as a generic widget library. The only evidence i have to support this is that a Form's ActiveControl is a TWinControl:
property ActiveControl: TWinControl;
That doesn't mean that Delphi could be, or must be, limited to windowed controls. The VCL widget library could be extended to support giving focus to windowless controls.
But perhaps Delphi already supports windowless controls, and i just don't realize it? Is there already an established mechanism in Delphi to support giving focus to TControl's? But i'm a reasonably smart guy, and i'm pretty sure Delphi's VCL cannot do what other widget libraries can do.
Which then leads to another question: how much work would be be to subclass forms and such to support it? Is there someone else out there, perhaps someone on TeamB, who's much smarter than i, who has already tried it, and come to the conclusion that it's impossible?
i'm asking now, up front, if trying to add windowless control support is damn near impossible (i.e. futile) - so that i don't spend weeks on it for nothing. i'm trying to draw on the knowledge of a community of Delphi developers.
i'm asking a question.
It's futile to build windowless controls and fit them into Delphi's VCL framework.
You bring up Internet Explorer as an example. But in that case, it's entirely in charge of everything that resides on it. It has its own internal notion of what the active control is, but think about what it looks like from the outside: It's just one giant control. When you ask the OS what has focus, the single browser control has it, no matter which of the browser's subcontrols appears to have focus.
When you press Tab, it looks to the OS as though the browser has simply consumed a tab character, just like edit controls do. Edit controls move the cursor over a few spaces and add tab characters to their internal buffers; browser controls move the cursor to another region of the display.
You're thinking of doing all this on a Delphi TForm. Delphi forms already have a framework for managing the active control and handling keystrokes, and you're going to have to fight it all. If you want windowless controls, go the Internet Explorer route and build your own container control to hold them so that you can remain in charge of everything that happens inside it.
Your container can be a VCL control, but the things you put on it probably can't — they'll still be expecting to use the VCL focus- and keyboard-handling rules. Notice how you can't put ordinary Windows controls in Internet Explorer, either. Anything you put there needs to go through specific ActiveX interfaces. Maybe you'll need interfaces, too, or maybe you can just make your own set of control classes that descend from some special ancestor class you design to work with your container. Don't start with TGraphicControl; it's too entrenched in the VCL to be usable as the basis for your offshoot control library.
It will be a lot of work, but then again, so was Internet Explorer.
Yes, it is futile.
And it's not Delphi's fault, you're just fighting Windows itself.
If you need a control that behaves like a windowed control, use a windowed one.
And you're right, trying to recreate the whole API stack of windowed controls from scratch is a pain.
Yup, you pretty much have it figured out. Using windowless controls means that you lose everything Windows can do to help you. Having more than a couple on a single actual window is pain.
Most of these programs were most likely not originally developed using RAD type tools so had no choice but to re-invent the wheel. One of the largest advantages of Delphi is the deep VCL and 3rd party component support to provide the look you desire.
One technique that I have used with great success to reduce the amount of window handles used in a complex (tax preparation) form based application was to draw the text on a canvas, and moved a single TCustomEdit decendant to the position the user was editing. It was trivial to capture the TAB/Up/Down keys and move the edit to the appropriate position. The challenge we discovered was in drawing a hot rectangle around the mouse hovered field. We ended up with a grid array of TObject, where the array element would be nil (no field), a TLIst (grid contains multiple fields) or a a class that contained our field descriptor. This reduced the amount of range checks we had to perform since it was more likely that the box only contained a single field, or at most 4 fields.
fpGUI Toolkit is an example of what you want. The latest fpGUI code in the source code repository is based on a multi-windowed design. That simple means every widget/component has a window handle, but Windows or Linux does nothing with that window, other that basic notification messages (mouseenter, mouseexit, etc). fpGUI still has full control over where each component goes, if they are focusable, how they look etc. Some widgets/components in fpGUI are non-windowed components too. eg: TfpgScrollbar, TfpgMainMenu, the button in a ComboBox etc.
If you want a true non-windowed version, mean there is only one top-level window that has a window handle, all other widgets/components inside that window doesn't actually exist to the OS (they have no window handles), then fpGUI can help too. The initial design of fpGUI Toolkit was based on such a design. Again, look in the source code repository for the v0.4 branch of code. I that design, fpGUI had to handle absolutely everything, creating mouseenter/mouseleave events, translate co-ordinate systems for container components, handle (fake) component focus states etc... Yes the initial design is a LOT of work, but then you have a very portable framework which can easily be applied to other OSes too.
And yes, fpGUI is fully implemented in the Object Pascal language using the Free Pascal compiler to give me cross-platform support. Currently fpGUI runs on Windows, Linux (32 & 64-bit), Windows Mobile and Embedded Linux (ARM) devices.
I have no idea of what your problem really is, here, but I think this little history may be relevant...
We have an application which fills out a dozen forms. The user may fill out additional forms, and also change values filled out by the application it self.
Now, in our first implementation, we used windowed components for every single input field, so that the fields could receive focus and input. That turned out to be a big problem, because all this windows took a lot of resources.
We now have windowless controls for every input field. That means that all we end up with, is a combined drawing of the form and its input fields. When the user clicks inside the drawing, or uses some keystrokes to move/set focus, we create a new windowed control for the clicked field. When the user moves to the next input field, we destroy the first window, and create a new one. This way we only have one windowed control which again gave us a nice speed improvement.
Again - I have no idea of what you really want to manage. TWinControl is a TWinControl for a reason, but there may be a solution to what you want, what ever that would be...
I think fgGUI may help you out.
Do check its Wiki first.
I think you can use this framework for your application in Delphi as it is written totally in Pascal. Actually it is based on FreePascal ;)
HTH
I have a Delphi 7 application that has two views of a document (e.g. a WYSIWYG HTML edit might have a WYSIWYG view and a source view - not my real application). They can be opened in separate windows, or docked into tabs in the main window.
If I open a modal dialog from one of the separate forms, the main form is brought to the front, and is shown as the selected window in the windows taskbar. Say the main form is the WYSIWYG view, and the source view is poped out. You go to a particular point in the source view and insert an image tag. A dialog appears to allow you to select and enter the properties you want for the image. If the WYSIWYG view and the source view overlap, the WYSIWYG view will be brought to the front and the source view is hidden. Once the dialog is dismissed, the source view comes back into sight.
I've tried setting the owner and the ParentWindow properties to the form it is related to:
dialog := TDialogForm.Create( parentForm );
dialog.ParentWindow := parentForm.Handle;
How can I fix this problem? What else should I be trying?
Given that people seem to be stumbling on my example, perhaps I can try with a better example: a text editor that allows you to have more than one file open at the same time. The files you have open are either in tabs (like in the Delphi IDE) or in its own window. Suppose the user brings up the spell check dialog or the find dialog. What happens, is that if the file is being editing in its own window, that window is sent to below the main form in the z-order when the modal dialog is shown; once the dialog is closed, it is returned to its original z-order.
Note: If you are using Delphi 7 and looking for a solution to this problem, see my answer lower down on the page to see what I ended up doing.
I'd use this code... (Basically what Lars said)
dialog := TDialogForm.Create( parentForm );
dialog.PopupParent := parentForm;
dialog.PopupMode := pmExplicit;
dialog.ShowModal();
I ultimately ended up finding the answer using Google Groups. In a nutshell, all the modal dialogs need to have the following added to them:
procedure TDialogForm.CreateParams(var Params: TCreateParams);
begin
inherited;
Params.Style := Params.Style or WS_POPUP;
Params.WndParent := (Owner as TWinControl).Handle;
end;
I'm guessing this does the equivalent of Lars' and Marius' answers in Delphi 7.
Is the dialog shown using ShowModal or just Show? You should probably set the PopupMode property correct of the your dialog. pmAuto would probably your best choice. Also see if you need to set the PopupParent property.
First of all, I am not completely sure I follow, you might need to provide some additional details to help us understand what is happening and what the problem is. I guess I am not sure I understand exactly what you're trying to accomplish and what the problem is.
Second, you shouldn't need to set the dialog's parent since that is essentially what is happening with the call to Create (passing the parent). The dialogs you're describing sound like they could use some "re-thinking" a bit to be honest. Is this dialog to enter the properties of the image a child of the source window, or the WYSIWYG window?
I'm not sure I quite understand what you are getting at, but here's a few things I can suggest you can try...
This behaviour changes between different versions of Delphi. I'd suggest that this is due to the hoops they jumped through to support Windows Vista in Delphi 2007.
If you are using Delphi 2007, try removing the line from the project source file that sets the Application.MainFormOnTaskBar boolean variable.
With this removed, you should be able to use the various Form's BringToFront / SendToBack methods to achieve the Z-ordering that you are after.
I suspect that what you've discovered has been discussed on this link
Of course, I may have just missed your point entirely, so apologies in advance!