My first component - multiple questions lazarus / 5-Lazarus Extra Components ---------------------------------------------------------------------- Marko · 2007-10-19 11:28 I'm creating a component for a program I'm writing and I have ran into some problems. I'm not very experienced in this (this is my first component)... 1. I tried to use TCustomControl as base, and while in windows everything worked perfectly, under Linux every window/object/whatever that goes over my component leaves a mark on it. I was unable to resolve this myself, so I decided to base it on TCustomPanel. Maybe someone can write why did this happen, just to know in future (I don't plan to revert back to TCustomControl) 2. This component is basically set of other standard components drawn on a panel. Second problem is that in design time I can move those labels, radio buttons etc. that are placed on that panel which is a basis of component. I'd like to change this behavior in a way that when I click anywhere above the panel in design time, panel gets selected, I shouldn't be in able to click or in any other way select those components inside the panel. This is an issue with which I can live (I'll create components dynamically in my program, so I won't notice it in use anyway), but it would be neat to fix it 3. On that same panel I have 3 edit boxes. For some reason first editbox always gets focus when program is started, while I want it to be 3rd. boxname.setfocus doesn't seem to have any effect. 4. Procedure Poravnaj looks really ugly (at least for me). I am convinced that there is a way to trim down all that repeated code into few lines, but I didn't have any luck with it. 5. Last and biggest problem are radio buttons. While same code works perfectly on Windows, under Linux whenever I start clicking those radio buttons program simply exits without any error message. All I get is 'Execution stopped', and if I run it from console, it spits up 'Segmentation fault (core dumped)'. I am pretty sure that procedure PrimjeniIzmjene is cause of this but I don't know how to fix it. I don't quite understand for what is that 'inherited' actually used, and in which form. For those with sharp eye, this whole function is slightly modified code from radiobutton.inc, which comes with Lazarus. Maybe they're killing each other? I have uploaded code here and here just in case In the end, I want to thank everyone for trying to help. If you see any design flaws (and there are quite a few I guess), please, but please propose a solution/better replacement. I want to make sure that in some future, more important project, I don't recreate same mistakes. TY! Marko ---------------------------------------------------------------------- Marko · 2007-10-20 23:47 Anyone? ---------------------------------------------------------------------- Phil · 2007-10-20 23:59 Quote from: "Marko"Anyone? Why put a bunch of controls into a custom "control"? Why not just put the individual controls on a form? Normally a custom control is just that - a single control with a specific purpose. ---------------------------------------------------------------------- Marko · 2007-10-21 11:24 Because I need about 32 groups of these controls on a form. It's much, much easier to manipulate data if they are grouped. I initially put individual controls on the form, but then code was a mess. With component like this that groups them, I can shorten code for about 90%. Now does anybody now how to solve at least problem number 5? Tnx! ---------------------------------------------------------------------- Phil · 2007-10-21 14:37 Quote from: "Marko"Because I need about 32 groups of these controls on a form./quote] 32? Something about that many doesn't sound right for a single form. Maybe you could describe what UI approach you're doing - that is, why you need 32 groups of controls on one form. Thanks. -Phil ---------------------------------------------------------------------- Marko · 2007-10-21 21:24 Uf why don't you just believe me and try to answer my question? :-P Ok, here's description. I have a "database" (it's not actually a database, but normal file) which contains information about people (football players to be precise). I also have a form which I have to fill, 18 such fields for each team. User inputs registration number of a player, and program retrieves other data and fills up rest of form, enabling user to view and edit data if necessary, and save it back to "database". Later I have to print the form. It would be very unnatural to separate these fields into smaller groups, and it would be very confusing for users, for a simple reason that it matters in which order these fields are, and it would be a hell to edit order of players later if user made a mistake entering data. So group of 18 such 'groups' (components) is necessary on one form at the time. As I said before, I already made version where i simply put all components directly onto form and it works. Problem is that manipulating data that way is extremely complicated cause I have to specifically name each control and make the same tasks over and over, just with different control names. This led to completely messy code and I decided to recode it with different approach. So my objective is: - Create component with all required fields to enter/edit data for single player - Component will be in able to accept records directly from file, so I read n bytes from file and send them to component, and component fills up all the fields, no need to say what goes to which box/label inside of my program, component will handle this. - Component can autoresize with the form or whatever container it is in... - Component will take care of checking what kind of data user is entering, and try to prevent errors - In program I can simply make an array of such components, and create them in simple for loop. Such approach makes it much easier to save data, copy it somewhere or whatever else, I only need one loop for everything that I'm doing. Before, I had to name each component on the form and tell it what to do (6 labels/editboxes * 18 players * 2 teams = 216 controls that I had to call by name and tell them what to do). I don't mean to be rude, but, do I now deserve to know why does it SEGFAULT on Linux while clicking those radio buttons? As I said, on Windows it works the way I want it to work... (I mean the part i finished til now) Thanks for the effort ---------------------------------------------------------------------- Phil · 2007-10-21 21:36 Quote from: "Marko"I don't mean to be rude, but, do I now deserve to know why does it SEGFAULT on Linux while clicking those radio buttons? As I said, on Windows it works the way I want it to work... (I mean the part i finished til now) Sorry, I can't help you with Linux since I don't use it. Now I understand what you're trying to do and, forgive me, but it still seems like an unnatural UI. Normally when we have multiple records, we provide user access to them in one of two ways: 1. Display one record at a time on form and use scroll bar or TUpDown or something like that so user can navigate between them. 2. Use a TStringGrid where each field of the record corresponds to a column in the grid and each record is a row in the grid. If the column types supported by TStringGrid aren't adequate to your needs, you might take a look at the TOvcTable control here: http://wiki.lazarus.freepascal.org/OrphPort Thanks. -Phil ---------------------------------------------------------------------- Marko · 2007-10-21 22:15 I don't know if you have ever seen those terminals in some big companies, it's a matter of past now, but they enabled users to fill up whole forms quickly, and that's the kind of functionality I'm trying to achieve. And as I said I've already done it, and users are quite happy about it because it's very efficient. So I don't want to change user interface much (I'll just graphically enhance it), but I really want to change the way my code looks right now. That's why I'm making this component. About your alternative suggestions - first 2 simply can't do. OrphPort could but I prefer to stay with the kind of interface users are used to. OrphPort seems to be table-like, and I'd like to avoid that. Phil, thank you for your effort to help. As you're not familiar with Linux maybe someone else will know what's happening there. If I could ask just a bit more of your time to look at procedure Poravnaj. Is there a way to avoid this repeating of code known to you? Thank you! ---------------------------------------------------------------------- Phil · 2007-10-21 23:56 Quote from: "Marko"Phil, thank you for your effort to help. As you're not familiar with Linux maybe someone else will know what's happening there. If I could ask just a bit more of your time to look at procedure Poravnaj. Is there a way to avoid this repeating of code known to you? I don't see anything really wrong with Poravnaj. I suppose you could shorten it a bit by casting the control types that descend from TWinControl together and those that descend from TGraphicControl together, but there's nothing wrong with doing it like you did - this way it's explict and clear what you're doing. There are 3 places where you're calling inherited that probably aren't necessary because there's no ancestor with that same name. In TRadioButton.ApplyChanges, they're calling inherited because they want its immediate ancestor's method (TCustomCheckBox.ApplyChanges) to be called. Have you tried it with other widgetsets like GTK2 and Qt? Since it works on Windows but not, presumably, with GTK, then I would suspect a widgetset issue rather than an FPC or LCL issue. Since controls like TCustomPanel have ChildClassAllowed set to True (as do most TWinControl descendents), they should be able to handle having child controls like this, but it's possible that this particular combination created at runtime doesn't work quite right due to a GTK widgetset bug. Orpheus's TO32FlexEdit control (a descendent of TCustomEdit) has an optional child button inside it - really handy. But this isn't supported on all widgetsets. I just tested it again: works fine on Windows, ignored with Carbon and GTK, crashes with Qt. But of course TCustomEdit isn't supposed to have child controls (ChildClassAllowed=False). Thanks. -Phil ---------------------------------------------------------------------- Marko · 2007-10-22 11:38 Thanks for the tip about that inherited, I wasn't sure should I put it there or not, but it doesn't change anything. I've tried to compile it with gtk2, but it still crashes... Maybe I need to put some more checks? Aha, I think I know what's the problem now, just not sure how to solve it. On windows, radio buttons are unchecked by default. Linux/gtk/don't know what sets them checked by default. The problem is that radio button can't be unchecked, it can only be unchecked if you check another radio button in the same group (container), while unchecking works under windows perfectly. So i tried button.checked := false after component creation but that does nothing, radio button remains selected. Actually, even if you put a single RadioButton on a form, you can't change it's Checked property in Object Inspector, it always remains True, and this is not how it behaves in Windows. I would hate to have to create another (hidden) radio, so is there an alternative? Hmm I guess I could use CheckBoxes... Thanks! ---------------------------------------------------------------------- Phil · 2007-10-22 13:53 Quote from: "Marko"I would hate to have to create another (hidden) radio, so is there an alternative? Hmm I guess I could use CheckBoxes... I think I see what your problem is. Only one radio button in each group is selected at a time and by group this means all radio buttons in a TRadioGroup or on a TPanel. Since you have only one radio button on the panel, it is selected by default and each panel's radio button is selected. I believe that's the way it should work. I assume that you want only one radio button on the entire form selected at a time. If so, what you'll probably need to do is use check boxes and in the check box's event handler when it gets checked it needs to manually uncheck all other check boxes (or at least the one that's checked elsewhere on the form). Thanks. -Phil ---------------------------------------------------------------------- Marko · 2007-10-22 14:46 I did it when I posted and it worked. All I did is replaced TRadioButton with TCheckBox declaration, and did the same change where it was necessary, and it worked. I'm not sure that it's expected behaviour of radio buttons, cause Lazrus in windows, and Delphi behave one way, and Lazarus in Linux the other way. Either way, there's something wrong with radio button, because, IMHO, it should behave the same on both systems. Marko ---------------------------------------------------------------------- Phil · 2007-10-22 16:35 Quote from: "Marko"Either way, there's something wrong with radio button, because, IMHO, it should behave the same on both systems. Because both Delphi and the Lazarus widgetsets implement most VCL/LCL controls using underlying native controls in GTK, Carbon, etc., there may sometimes be differences between and not just how they look visually. If you can isolate an example of how TRadioButton behaves differently on Win32 and GTK widgetsets, please log it as a bug, at least so it's documented. Glad to hear things are working for you now. Thanks. -Phil