[Solved]A couple of GUI issues

General help with the Ecere Cross Platform GUI toolkit: Window, common controls, events, etc.
Help with the 2D Graphics library: Surface, Display, Bitmap, Font and others.
Post Reply
samsam598
Posts: 212
Joined: Thu Apr 14, 2011 9:44 pm

[Solved]A couple of GUI issues

Post by samsam598 »

This is an execise which list all files with full path under a selected directory.Given below sources:

Code: Select all


import "ecere"

class Form1 : Window
{
   text = "Form1";
   background = activeBorder;
   borderStyle = sizable;
   hasMaximize = true;
   hasMinimize = true;
   hasClose = true;
   size = { 576, 432 };

   EditBox txtDir { this, text = "editBox1", size = { 214, 19 }, position = { 144, 24 } };
   Button btnView 
   {      
      this, text = "(V)iew", altV, position = { 488, 24 };

      bool NotifyClicked(Button button, int x, int y, Modifiers mods)
      {
         if(!strcmp(this.txtDir.contents,""))
         {
            MessageBox {text="Error",contents="Text can not be blank.",type=ok,master=this}.Modal();
            return false;
         }
         listDir(txtDir.contents);
         return true;
      }
   };
   EditBox txtFiles { this, text = "editBox1", size = { 534, 323 }, position = { 16, 64 }, hasHorzScroll = true, true, fullRender = true, readOnly = true, true };
   Label label1 { this, text = "请输入文夹件路径:", size = { 116, 13 }, position = { 24, 24 } };

   bool OnCreate(void)
   {
      
      return true;
   }

   void listDir(char* path)
   {
      FileListing listing {path};
      while(listing.Find())
      {
         if(listing.stats.attribs.isDirectory)
         {
            listDir(listing.path) ;
         }
         else
         {
            this.txtFiles.AddS(listing.path);
            this.txtFiles.AddS("\r\n");
         }
      }
   }
}

Form1 form1 {};
                                       
Questions:
1.After the button BtnView is pressed,nothing fills the txtFiles unless left button is down inside the txtFiles area;if I add Clear() method of txtFiles at the begining of btnView.NotifyClick,only the first file is added in the txtFiles automatically,still need to press the left button inside the txtFiles to retrieve the remaining files;
2.After the files with full path under a selected folder fill in the txtFiles,HScroll & VScroll bar do not show unless press left button at the edge(something the like,not very sure) of the txtFiles for a second time;
3.Which property or function can I use to set the txtDir get focused at the program startup,suppose it should be coded in the form's OnCreate()?
4.Adding a line of string to EditBox use EditBox.AddS,while I noticed that for ListBox(? not sure)it uses ListBox.AddString,the naming convention is not consistent.

Please help.Thanks.

Regards,
Sam
Last edited by samsam598 on Tue Aug 23, 2011 8:26 pm, edited 2 times in total.
jerome
Site Admin
Posts: 608
Joined: Sat Jan 16, 2010 11:16 pm

Re: A couple of GUI issues

Post by jerome »

Hi Sam.

1. First of all EditBox is a very old class that never got a proper clean up. Don't look for consistency, it's not there. We plan to have a cleaner design with user reviews for a new version of the GUI engine, but at the moment we are trying to focus on making everything stable and functional.

This is a topic for discussing future improvements to the GUI toolkit, and Mantis can be used to keep track of these improvements and their progress.

So AddS is like a 'low level' method meant to be fast, e.g. if you have a lot of text to output. After calling AddS (e.g. multiple times), you're expected to call EditBox::SetViewToCursor, which will ensure the cursor is kept visible and update the control. At the minimum a call to Update(null) is necessary for the control to redraw itself.

The higher level version of AddS, 'PutS', calls AddS, SetViewToCursor, and mark the control as modified. That is the method expected to be called most often by the user (AddS is more for internal use), unless you need the performance gain that you get from calling AddS multiple times.

There is also a Printf (printf like formatting) and PutCh (single character) output function. There is not yet a Print/PrintLn-like method in the EditBox because it predates those (but should come in the future).

2. I see that behavior. That is because EditBox::SetViewToCursor is expected to be called after calling AddS. Calling it or using PutS instead of AddS will fix this as well.

3. Calling txtDir.Activate(); in OnPostCreate() will do this for you. It seems to work in OnCreate() as well. The difference between OnCreate() and OnPostCreate() is that OnPostCreate happens at the very end of the window creation process, all the display have been set up, graphics have been loaded, and any child or slave windows have been created as well.

In the next generation GUI we hope to come up with an easier way to define: The tab ordering of the controls, and the control active by default.

4. You have a good point about EditBox::AddS vs ListBox::AddString, although I never thought to compare these two, the ListBox and EditBox being used for very different purposes. AddString came as a convenience function for ListBoxes working with String data types that combines AddRow/SetData in a single function call. The GUI toolkit has a very long history (about 14 years) and the last GUI review / cleanup has been a long time ago, we need a new usability review :)

Bonus suggestions:

- In eC 'this.' is not required and I generally suggest to omit it, unless it is to distinguish between a member variable an overshadowing local variable or argument with the same name.
- Buttons can have be the 'default' buttons for the dialog, they get a black border and 'Enter' anywhere in the dialog presses them (This is amazingly a cancellable process in Ecere! The button doesn't click until you release the Enter key, and you can cancel by using the Tab key or Escape key while the button is held down :D ). Set isDefault = true;
- Set tabCycle = true on dialogs, so that you can use the Tab key to cycle between controls
- Ecere has very powerful anchors to make dialogs rescale to different sizes. You can define the distance between any edge of the control and the parent window's corresponding edge either relatively (a percentage) or to a fixed number of pixels. Checkout the 'anchor' property under the 'Layout' properties category of any Window.
- Set minClientSize instead of size to guarantee that a window cannot be resized smaller than an area in which the dialog will look good. Or you can set clientSize to guarantee a number of pixels in the client area, regardless of how much space the window decorations (title bars/borders) will take.
- I'm not a fan of the carriage return/new line combination, so internally \r characters are never used. They are ignored when you do AddS("\r\n") so you might as well just say AddS("\n"). If you want "\r\n" to be saved to a file for each new line you can pass true to the EditBox::Save method for the 'lf' parameter.
- !txtDir.contents[0] is a simpler, equivalent check to !strcmp(txtDir.contents,""), and 'ok' is the default type for a MessageBox so you can omit it
- The return value of NotifyClicked is for chaining mouse events and it's a rather advanced topic. You can simply return true regardless of error or not.
- You can set nativeDecorations = true; to use native system decorations. I've recently completed the support on Windows and there is partial support on X already.
- I changed the EditBox and Labels using a connected label, as I discussed in the other thread.

Here is my tweaked version of your sample code:

Code: Select all

import "ecere"
 
class Form1 : Window
{
   text = "Form1";
   background = activeBorder;
   borderStyle = sizable;
   hasMaximize = true;
   hasMinimize = true;
   hasClose = true;
   tabCycle = true;
   nativeDecorations = true;
   minClientSize = { 576, 432 };
 
   EditBox txtDir { this, text = "请输入文夹件路径:", size = { 214, 19 }, position = { 144, 24 } };
   Label lblTxtDir { this, labeledWindow = txtDir, size = { 116, 13 }, position = { 24, 24 } };
   Button btnView 
   {      
      this, text = "(V)iew", altV, position = { 488, 24 };
      isDefault = true;
 
      bool NotifyClicked(Button button, int x, int y, Modifiers mods)
      {
         if(!txtDir.contents[0])
            MessageBox {text="Error",contents="Text can not be blank.",master=this}.Modal();
         else
         {
            txtFiles.Clear();
            listDir(txtDir.contents);
         }
         return true;
      }
   };
   EditBox txtFiles { this, anchor = { left = 16, top = 64, right = 18, bottom = 17 }, hasHorzScroll = true, hasVertScroll = true, readOnly = true, multiLine = true };
 
   bool OnPostCreate()
   {
      txtDir.Activate();
      return true;
   }
 
   void listDir(char* path)
   {
      FileListing listing {path};
      while(listing.Find())
      {
         if(listing.stats.attribs.isDirectory)
         {
            listDir(listing.path) ;
         }
         else
         {
            txtFiles.AddS(listing.path);
            txtFiles.AddS("\n");
         }
      }
      txtFiles.SetViewToCursor(true);
   }
}
 
Form1 form1 {};
samsam598
Posts: 212
Joined: Thu Apr 14, 2011 9:44 pm

Re: A couple of GUI issues

Post by samsam598 »

Hi Jerome,

Really appreciated.I've learnt a lot.God I love this place,just like one teacher to one student :D
I have a couple of more questions here:
1.Still I don't quite understand what's the purpose of labeledWindow;
2.How to arrange the position of the button btnView ,when the size of the form changes,the position of the button to the right edge of the form is fixed,and the size of the button is fixed as well?
3.Beside the default button (Enter),is there also a default cancel button(ESC)?

Thanks.
jerome
Site Admin
Posts: 608
Joined: Sat Jan 16, 2010 11:16 pm

Re: A couple of GUI issues

Post by jerome »

That's what I am here for =) At the moment I realize the documentation is sparse, and the Ecere community is still small. I am happy to explain how everything works to help the community grow :D

1. The labeledWindow is to tell the label which control it will label. When the label is thus connected to its control, there are 2 main things that you get:
- When you click the label, the control is activated
- You can get the hotKey underlined
Additionally, it allows you to define the label of the control (The 'text' property) within the control itself, as opposed to separately. It keeps things tidy. I suggest you use the lblControlName convention and define the label right above or right below the control it labels as well.

2. If you want a button to be 80x24, always at 10 pixels of the right edge of the parent, and at 30 pixels from the top, you say:

Code: Select all

Button button { this, size = { 80, 24 }, anchor = { top = 30, right = 10 }, text = "Push me" };
Some other useful anchors:
anchor = { left = 10, top = 20 } is the same as position = { 10, 20 }
anchor = { left = 0, top = 0, right = 0, bottom = 0 } will fill out the entire parent's client area
anchor = { } will make the control floating in the very center of the parent's client area
anchor = { horz = 10, vert = 20 } will offset the center of the control 10 pixels to the right, and 20 to the bottom of the parent's client area center
anchor { left = 0.1, top = 0.2 } will keep 10% of space to the left and 20% of space to the top

3. You can make a cancel button with a 'escape' hotKey this way:

Code: Select all

Button btnCancel { this, text = "Cancel", hotKey = escape, NotifyClicked = ButtonCloseDialog, id = cancel, size = { 80, 24 }, anchor = { right = 10, bottom = 10 } };
An OK button would typically be:

Code: Select all

Button btnOK { this, text = "OK", isDefault = true, NotifyClicked = ButtonCloseDialog, id = ok, size = { 80, 24 }, anchor = { right = 10, bottom = 50 } };
These will return 'ok' or 'cancel' as the dialog result, for example if you use the Modal() method to obtain a result from the dialog. You can obtain the result of even a non-modal dialog by overriding the NotifyDestroyed method of the dialog.

You can also check id inside a NotifyClicked method, this lets you use the same method for multiple controls. If you play with the IDE's method sheet (F4) you will see how you can override, detach, and reattach methods to controls.

Regards,

Jerome
samsam598
Posts: 212
Joined: Thu Apr 14, 2011 9:44 pm

Re: A couple of GUI issues

Post by samsam598 »

Thanks,one last question regarding the anchor.
2. If you want a button to be 80x24, always at 10 pixels of the right edge of the parent, and at 30 pixels from the top, you say:

Code: Select all

Button button { this, size = { 80, 24 }, anchor = { top = 30, right = 10 }, text = "Push me" };
As the left property's set in the property window,there is no way to let this field (left=xx)blank at this moment.The only way to do is to modify in the source editor.Please take note.Thanks.
jerome
Site Admin
Posts: 608
Joined: Sat Jan 16, 2010 11:16 pm

Re: A couple of GUI issues

Post by jerome »

Hi Sam.

You're right, I think there is a bug there. However I think it only affects the edition of the individual fields when you 'expand' the anchor property.

You have 2 other options which seem to work fine right now:

1. Edit it in the top box, where all members are on one line (i.e. top = 24, right = 20).
2. Or select the drop down, and click (toggle) the edges so that top and right are grayed.

you also have the source editor option. The form editor is there to get people started but is a bit experimental in nature and buggy sometimes. We use the code editor a lot. The form editor is useful to do some visual adjustments or quickly get a new GUI going. Of course we hope to make it perfect one day :)
jerome
Site Admin
Posts: 608
Joined: Sat Jan 16, 2010 11:16 pm

Re: A couple of GUI issues

Post by jerome »

Sam, I've just fixed that. You can pull the fix from git.

Thanks for reporting the bug :)

-Jerome
Post Reply