I use this code: How to make a combo box with fulltext search autocomplete support? to create custom TComboBox control with searching.
Everything was working fine but I decided to add bitmaps (pictures) into it using this method: ComboBox Simple with Bitmap
But when I added the second code I lost the searching functionality. To enable Owner drawing I added csOwnerDrawFixed style to control in constructor
constructor TComboBox.Create(AOwner: TComponent);
begin
...
Style := csOwnerDrawFixed; ; << Added to enable owner draw
end;
How can I combine these two codes? The strange thing is when I run the project I can see the control redrawing correctly first time but then all data are lost and no drawing is done.
#Rohit Gupta: Actually it is pretty easy to merge that 2 codes: simply place 2nd code into 1st one and rename class :)
I did this but the code is not working - painting the control causes freezing of software and I could not solve this issue that is why I asked for help.
#Warren P: you are right, the better is to create custom control which handles everything.
I created my own control which is basically TEdit with owner draw and TListBox with owner draw and TSpeedButton which works fine:
I need to do some tweaking now and finished control will be available on my blog.
If someone is interested then grab it later on http://unsigned.sk/blog/ (I will post comment here once finished).
Thanks to all for ideas!
Related
My goal is to create a simple forms editor like the one that we find on Delphi IDE.
Right now the user can select and add the components making it parent of a TPanel that is the holder of the form. For simplicity, please consider also TPanel as the visual components added to the form.
I have 2 missing parts I want to find out ideas/code to help complete:
1 - how to move the created visual component? The same effect that in IDE for moving the visual component, for example Tpanel, around, chaning its top and left position
2 - how to draw that hooks for the component with focus on the form editor
3 - how to resize using the hooks
I only want the part related to handle the visual part. I am not generating DFM or anything like that.
Simply put your moving code needs to do this:
When the mouse goes down, check if the mouse position is over a control that can be dragged. If so, then set a variable named FDragControl to refer to that control. This code lives in an OnMouseDown event handler.
When the mouse moves, if FDragControl is not nil, move the control. This code lives in an OnMouseMove event handler.
When the mouse goes up, set FDragControl to nil.
That's pretty much all there is to it. The main nuance is that you must also remember the X, Y values of the mouse when the drag commenced. So in your OnMouseDown handler you write:
FStartMousePos := Point(X, Y);
FStartDragControlPos := Point(FDragControl.Left, FDragControl.Top);
And then in the OnMouseMove your position code reads:
FDragControl.Left := FStartDragControlPos.X + (X-FStartX);
FDragControl.Top := FStartDragControlPos.Y + (Y-FStartY);
You will also need to capture the mouse when you start dragging.
The resizing code is similar. Again, you need to decide in the OnMouseDown that you are resizing rather than dragging, but the code still involves handling mouse down, move and up events.
As for painting, you need to force a repaint whenever one of your event handlers changes a property that will influence the visual appearance of your form. You can use the value of FDragControl to decide whether or not to use special drawing of your control and indicate that it is being dragged. And likewise for resizing.
I've not coded up a full working implementation since your question is high level and conceptual. The implementation is down to you.
// I have made this an answer as I have just read your latest update which really should have been made as an edit to your original question but, anyway.
You can download the Cindy Components Pack and use the cyResizer Component which will do pretty much everything you need and is very customisable as well.
You can download it from here: http://sourceforge.net/projects/tcycomponents/
Searching more for an answer I could find these articles:
How to Move and Resize Controls at Run Time
http://delphi.about.com/library/weekly/aa102505a.htm
How to Add Size Handles to Controls being Resized at Run-Time
http://delphi.about.com/library/weekly/aa110105a.htm
Pretty much with all the information to complete this task with source code example.
These articles show how to implement and use a TMover class. I have done it and work correctly.
I have also downloaded the TcyComponents Pack and used the TcyResizer. It is a full featured form editor with pretty much everything that is required for a Delphi like forms editor. I recommend. It comes with source code and works fine with XE2 version.
I've just started with Firemonkey, and still have a lot to learn with regards to the usage of styles, but there is something I can't get figure out.
I've learned how to simulate a TListView using styles. So I've made a style which adds a progress bar to a list item, let's call this ListItemStyleProgressBar.
Now I'd like two ListView instances on my form, one where the font of the TListItem is red, and one where the font is blue. How to achieve this? Can I make an style which 'inherits' from ListItemStyleProgressBar (ListItemStyleProgressBarRed)?
Next to that, I'd like to be able to 'style' these two listview instances, so have a style which shows a light back and a style which shows a dark back.
What confuses me is it seems the styling is needed to add functionality (add a TProgressBar to a TListItem) as well as to do styling for this added functionality.
Can anyone tell me what I'm missing here?
No. There is no inheritance mechanism for styles. There are two ways to solve your problem:
1) Create two (or more) very similar styles to represent each 'look'.
2) Make the changes at run-time either with the OnApplyStyleLookup method or, if you have a custom control, by overriding the ApplyStyle method.
In the latter case you'll need something like this:
procedure TMyClass.ApplyStyle;
var O: TFMXObject;
begin
O := FindStyleResource('background');
if O is TRectangle then
TRectangle(O).Fill.Color := claRed;
end;
I'm building a custom control which is to have multiple focus points. For example, within 1 control, let's say there's 3 regions (could be defined as a rect on the canvas) which are to be able to have focus. Depending on which one has focus, I don't want the default Windows dotted line around it, but some special handling. I know nothing about how to even give 1 custom control its own focus.
The original project was a single TPanel with a few VCL controls on it, each of course being its own window, thus having its own focus. But now I'm putting it into a custom class of its own, which these 3 controls will no longer exist (they were only there in version 1 as a prototype) and I need to now somehow mimic the focus in these different regions.
I guess similar to something as simple as a TListBox, where certain items within that control get the focus instead of the entire control its self.
Here's a picture to help demonstrate what I'm making...
The one on the top is the original with the buttons. But the one on the bottom is the new one I'm building which is all custom drawn.
To elaborate, I'd like to see if Windows already has special handling for this type of scenario before I go and re-invent the wheel.
I'm not looking for the "Easiest" way to accomplish this. And I also do not want recommendations to revert back to how I had it before, because there's many reasons I don't want 1 control with multiple other controls within. I just need a yes or no, with an explanation.
More
I just realized the main concern is the use of the tab key. The control has to first get the focus, start the focus on whichever sub-item it's supposed to, then respond to tab on my command until it reaches the end, then pass the tabbing over to the next control. Then it also needs shift+tab as well. How on earth would I implement this tabbing? That's where I got stuck, but it just struck me that this is the main reason I'm asking.
About the handling of the TAB key - it should be something like this: you handle the WM_GETDLGCODE message to indicate that you want to proccess the TAB key, ie
TMyControl = ...
protected
procedure WMGetDlgCode(var Msg: TMessage); message WM_GETDLGCODE;
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
...
procedure TMyControl.WMGetDlgCode(var Msg: TMessage);
begin
inherited;
Msg.Result:= Msg.Result or DLGC_WANTTAB;
end;
and the in the overriden KeyDown method you decide what to do in response of it, something like
procedure TMyControl.KeyDown(var Key: Word; Shift: TShiftState);
begin
if(Key = VK_TAB)then begin
if(ssShift in Shift)then begin
if(first subcontrol is focused) set focus to previous control on parent
else set focus to previous child area
end else begin
if(last subcontrol is focused) set focus to next control on parent
else set focus to next child area
end;
end else inherited;
end;
No you can't get windows to recognize multiple points of keyboard focus inside the same window handle, since each control with a window handle either has, or does not have, keyboard focus. The "inner focus" between multiple controls is up to you to sort out.
As you already knew, the most simple way to accomplish this is to have multiple sub-controls with their own window-handles, which is what you said you are doing:
TMyThreeEditControls = class(TControl) // parent has no window handle!!!!
protected
FEdit1:TEdit;
FEdit2:TEdit;
FEdit3:TEdit;
...
end
In the situation above, the parent control is a TControl, it creates several sub controls, in my example above, all three have their own window handles, and thus Windows can display keyboard focus when you hit tab, and handle mouse focus as part of Windows's common controls library's functionality.
In short, the "composite" approach where you include sub-objects (other controls) in your main control, which you are trying to move away from is in fact, the only way to let Windows do most of the work.
On the other hand, what you might be looking for is not a way to have a control paint itself, but some code to make something look like it is focused, in your own custom painting routines, if that is what you are looking for, you should look into the VCL source code or this link on about.com for examples on how to tell Windows to draw a focus rectangle, etc. The about.com link is an imitation and does not use real windows code to draw focus in a Windows-theme aware way.
Update: it is possible that what you are also looking for is the way to determine if mouse co-ordinates are within a specified rectangle (the rectangle represents a button in your case) and if so, to draw a "hot state" for the button. There are more sub-tasks than this to accomplish if you wish to build a control yourself, I recommend you study existing controls such as TStringGrid and TCategoryButtons in the VCL source code, to see the MouseMove, MouseDown, and MouseUp handling code you will need to do the things you are trying to do. In particular, StringGrid source code is the way to see how the "tab key" can be used within a single control with a single window handle, because in that control the tab key can be used (if the right options are turned on) to navigate among all the cells inside the string grid, as if each one was a separate control, even though it is all one control.
Another way to achieve this is to use one edit box that you re-use for each region that you want to have "focused". This is essentially how Delphi's grids work.
When the user clicks in that area (or hits the tab key into your control) you set the edit controls text to the data in that area, set the edit controls bounds to the area and make it visible. When the user exits the control (by clicking out of it or tabbing) you hide the edit control. If you make your control accept the tab key, you can make it "edit" the next area when they hit tab and exit it when they are in the last area.
Then it's just house keeping to make sure you store the entered data in the right spot in your component.
To thwart the nit-pickers, let me start with, I searched here with this and could not find an answer, and yes, also I did scroll through the "Similar questions."...
Adding shortcuts to a TForm
I want to drag and drop some shortcuts from the Desktop to a TForm in my application. I am using Anders Melander's brilliant Drag Drop Suite (DDS).
I tried putting a TImage on the form but the DDS does not drop to an Image so I added a TPanel with a TImage on it. I could then drop on the panel and assign the image to the TImage.Picture. Problem was the Panel has no Transparent Property so the shortcut on the form looks clunky with the visible Panel behind it.
I need to be able to drop to the TImage or make the underlying TPanel transparent.
Can anyone help with code-snippets for either of those options, or better yet, a method of dropping a Shortcut directly on to my Form.
Thanks
Coincidentally I needed to make a TWinControl (the base for every visible control with a window handle, including TPanel) transparent. I found numerous results and applied them to this answer.
It's been a while since I implemented drag and drop, but I assume you call some API and pass it the handle of the panel? That answers the question why you can't use TImage. TImage is a graphic control, a control without a handle, that relies on its parent for recieving messages and drawing itself.
It should be possible to use the form, though, since that has a handle too.
If the TImage is directly on the TForm, then let the TForm handle the drop, no TPanel needed. OLE Drag&Drop operations (which Ander's components implement) provide coordinates where dragging and dropping occurs. The TForm should be able to detect when a drag is over the area occupied by the TImage and what type of data is being dragged, and only allow dropping of supported types within that area, extracting the dropped data and updating the TImageas needed, and denying anything else that does not match that criteria.
What i am trying to accomplish is to create new touchkeyboard.
First i created buttons which i derive from speed buttons.
That done, now i need to create multiple buttons and layout them somewhere. This is were i get stuck.
I created a new component which i derive from TGraphicControl (this should be my new touchkeyboard), but i don't know how to add components to canvas. I actually don't know whether i'm supposed to add them to canvas or to some other component (eg. panel)!?!
Is my approach OK?
Thanks in advance.
If you're creating a custom visual control, you need to create the buttons and position them manually. For example:
TOnScreenKeyboard = class(TWinControl)
public
constructor Create(AOwner: TComponent);
end;
[...]
constructor TOnScreenKeyboard.Create(AOwner : TComponent)
var
TempButton : TSpeedButton;
begin
inherited;
TempButton := TSpeedButton.Create(self);
TempButton.Parent := self;
TempButton.Top := 10;
TempButton.Left := 15;
TempButton.Caption := 'A';
end;
You can put the button creation into a loop and position each one according to where it should be.
(I wrote this off the top of my head, and I don't write a lot of Pascal anymore, so there may be some minor mistakes! But it should get you started.)
Because of your wording and confusion between Panel, Canvas and custom controls in general, I assume you're a Delphi beginner. You need to learn about frames: embarcadero docwiki link on frames
Frames allow you to create re-usable portions of GUI. You use the IDE to "draw" the frame, you can then place that composite control (the frame) onto forms or other frames. It's a very powerful feature and it's conceptually very close to what other languages call "custom controls" (very close to what asp.net or WPF consider a custom control to be).
In the Delphi world, when you say "custom control", people would normally expect you to want to create an reusable control that's placed in a package and it's installed in the IDE. It's an fairly advanced subject. If that's what you want then I misunderstood the question, sorry.