|
|
Home » U++ Library support » ArrayCtrl, HeaderCtrl & GridCtrl » Embed editfields in ArrayCtrl
Embed editfields in ArrayCtrl [message #24264] |
Fri, 08 January 2010 00:30  |
mdelfede
Messages: 1308 Registered: September 2007
|
Ultimate Contributor |
|
|
Embedding Editfields in ArrayCtrl offers nice editing and filtering capabilities, and the function
offers a fast way to do it but.... it has also a couple of caveats :
1 - Embedded fields get frames, which is ugly inside the array
2 - Embedded fields grab ArrayCtrl rightclick context menu
This simple template solves both :
template<class E> class Embedded : public E
{
protected:
void RightDown(Point p, dword keyflags)
{
Ctrl *c = this;
ArrayCtrl *a;
while( (c = c->GetParent()) != NULL && ((a = dynamic_cast<ArrayCtrl *>(c)) == NULL))
;
if(a)
{
Rect cRect = E::GetScreenRect();
Rect aRect = a->GetScreenRect();
p.y += cRect.top - aRect.top - a->HeaderObject().GetHeight();
p.x += cRect.left - aRect.left;
a->RightDown(p, keyflags);
}
}
public:
typedef Embedded<E> CLASSNAME;
Embedded<E>() { E::ClearFrames(); }
};
It's usage is simple, just define your ctrl as, for example :
typedef Embedded<EditDouble> EditDoubleEmbedded;
Then use as a normal editfield in arrayctrl.
The field will get no frames and forward context menu clicks to its ArrayCtrl container.
Ciao
Max
|
|
|
Re: Embed editfields in ArrayCtrl [message #24271 is a reply to message #24264] |
Fri, 08 January 2010 13:45   |
 |
mirek
Messages: 14256 Registered: November 2005
|
Ultimate Member |
|
|
mdelfede wrote on Thu, 07 January 2010 18:30 | Embedding Editfields in ArrayCtrl offers nice editing and filtering capabilities, and the function
offers a fast way to do it but.... it has also a couple of caveats :
1 - Embedded fields get frames, which is ugly inside the array
2 - Embedded fields grab ArrayCtrl rightclick context menu
This simple template solves both :
template<class E> class Embedded : public E
{
protected:
void RightDown(Point p, dword keyflags)
{
Ctrl *c = this;
ArrayCtrl *a;
while( (c = c->GetParent()) != NULL && ((a = dynamic_cast<ArrayCtrl *>(c)) == NULL))
;
if(a)
{
Rect cRect = E::GetScreenRect();
Rect aRect = a->GetScreenRect();
p.y += cRect.top - aRect.top - a->HeaderObject().GetHeight();
p.x += cRect.left - aRect.left;
a->RightDown(p, keyflags);
}
}
public:
typedef Embedded<E> CLASSNAME;
Embedded<E>() { E::ClearFrames(); }
};
It's usage is simple, just define your ctrl as, for example :
typedef Embedded<EditDouble> EditDoubleEmbedded;
Then use as a normal editfield in arrayctrl.
The field will get no frames and forward context menu clicks to its ArrayCtrl container.
Ciao
Max
|
Actually, as long as you override RightDown, there is no need to make the menu indirectly. Remember, the problem we had was because there was a call to SetFocus after the menu handling...
No RightDown, no SetFocus...
Mirek
|
|
|
|
Re: Embed editfields in ArrayCtrl [message #24275 is a reply to message #24274] |
Fri, 08 January 2010 14:49   |
mrjt
Messages: 705 Registered: March 2007 Location: London
|
Contributor |
|
|
Except it doesn't work at all!
The problems:
- EditField doesn't have StdBar, are you thinking of EditText?
- As above for WhenMenu, just overload RightDown and call EditField::DoMenu
- I've also changed it to use ArrayCtrl::StdBar and set the ArrayCtrl cursor correctly to enable this, which is more in line with the way the ArrayCtrl works.
Here's my version:
#include <CtrlLib/CtrlLib.h>
using namespace Upp;
struct EditStringSpecial : EditString {
ArrayCtrl *GetArrayCtrl() {
for(Ctrl *q = GetParent(); q; q = q->GetParent())
if(ArrayCtrl *a = dynamic_cast<ArrayCtrl *>(q))
return a;
return NULL;
}
static void DoMenu(EditStringSpecial *x) {
class MenuBar bar;
x->MenuBar(bar);
ArrayCtrl *a = x->GetArrayCtrl();
if(a) {
a->SetCursor(a->GetLineAt(GetMousePos().y - a->GetScreenView().TopLeft().y));
bar.Separator();
a->StdBar(bar);
}
bar.Execute();
}
virtual void RightDown(Point p, dword keyflags) {
PostCallback(callback1(DoMenu, this));
}
typedef EditStringSpecial CLASSNAME;
EditStringSpecial() {
ClearFrames();
}
};
GUI_APP_MAIN
{
ArrayCtrl a;
a.AddColumn("Label");
a.AddColumn("Text").Ctrls<EditStringSpecial>();
for(int i = 0; i < 300; i++)
a.Add("Label " + AsString(i), AsString(i));
a.SetLineCy(Draw::GetStdFontCy() + 8);
a.Duplicating(true).Removing(true).AppendLine(true).Appending(true).Inserting(true);
TopWindow app;
app.Add(a.SizePos());
app.Sizeable();
app.Run();
}
Otherwise it's very nice, though it would be good to avoid the dynamic_cast.
One remaining problem is that if ArrayCtrl doesn't add anything to the menu then you end up with a hanging separator, but I don't what to do about that. It would be nice if MenuBar ignored these automatically.
[Updated on: Fri, 08 January 2010 14:57] Report message to a moderator
|
|
|
|
|
|
|
|
|
|
Re: Embed editfields in ArrayCtrl [message #24295 is a reply to message #24292] |
Sat, 09 January 2010 09:38   |
mdelfede
Messages: 1308 Registered: September 2007
|
Ultimate Contributor |
|
|
luzr wrote on Sat, 09 January 2010 00:47 |
Not to say anything bad about your templat - it is clever "not knowing enough about interface definition" design. But it is sort of overkill - if you are going to override RightDown, you can skip the part about translating mouse coordinates...
|
ArrayCtrl::RightDown() doesn't need a correct mouse point ?
Quote: |
....and invoking ArrayCtrl's RightDown and just create the menu of only ArrayCtrl items and call Menu::Execute in RightDown...
|
If I've right understood, you mean I should override EditField's RightDown(as I deed), just invoke ArrayCtrl's one (as in my template) but without need to translate mouse coords, then override also ArrayCtrl's RightDown() in order to invoke it's Menu::Execute ?
Besides that then I need to override ALSO the ArrayCtrl's RightDown (which forces me to derive from ArrayCtrl instead of using it directly), but how do then ArrayCtrl know on which row my mouse pointer is ? I think it's needed for row deletion, at least.
I added mouse translation just because on first try I didn't and the arrayctrl was always fetching the first row.
BTW, the best way would of course be to integrate the behaviour in ArryaCtrl, making it hook inside embedded ctrls menus, but then we would face again with the problem of Ctrls deletion, which can't be done without override Ctrls RightCtrl.
As you correctly pointed to me, the 'true' problem is not the ctrl removing from inside the callback by itself, but the fact that Ctrls RightDown tries to re-set focus on itself AFTER the callback execution.
Thinking a bit more, the solution should be :
1- Add the behaviour to ArrayCtrl, but...
2- Use your PostCallback way to handle the event
I think I'll try it today 
Max
|
|
|
|
Goto Forum:
Current Time: Wed Apr 30 01:49:03 CEST 2025
Total time taken to generate the page: 0.05246 seconds
|
|
|