Matthew Fairclough wrote:

> I would like to thank Ed and Paul for their responses and updates.  I
> just downloaded the latest tarball and everything works perfectly
> (though I must admit still having difficulty with ReportDesigner)

ReportDesigner isn't usable yet, but under heavy development.


> Dabo seems perfect.  The SimpleApps showed exactly what I need in terms
> of entry, edit, and search.  Also, ReportDesigner will allow me to
> create the reports I need (once I can figure out how to use it:)

No, ReportDesigner can't do that yet, and it will probably be on the order of months until it can.


> However, I'm having a little difficulty determining whether Dabo is
> sufficiently developed for someone like myself.  I have a feeling that I
> might be a few years too early. One of the main reasons for this is the
> documentation.  I understand that it is the last part of the agenda, but
> I am lost without it

You are indeed a bit early if you want a fully-developed toolkit with full instructions on how to use it. However, if you can afford to get your hands a bit dirty, from what you've said about your project with a little elbow grease I'm certain you could get a Dabo app up and running for your purposes.


> If someone can point me in the right direction, perhaps I can get a
> better grip on this.  Using the OneToManyApp as an example

I'm really kind of embarrassed that you are using the OneToManyApp, as it was never followed through with and doesn't completely work.


> 1.  Instead of opening a new app for every table (which would confuse my
> users no end), I have been trying to open each table as a separate tab
> (much like FieldSpecEditor).

First off, it isn't a new app for every table, but a new form for each entity. It could be that an entity comprises a number of underlying tables, but the users only care about the entity, not the composition of the underlying database.


> Each tab would be identical to the current
> forms.  In this way there is only one window, and if a user wanted to do
> other things (such as a report), they would just open another tab.  I
> haven't had any success with this.  How can this be done

First off, for testing purposes only, and just so you can get started, please temporarily set the OneToManyApp aside, and try out my new AppWizard, which is in the daboide/wizards directory and is called "AppWizardX". Pick one main table in your database, and only generate the app for that one table and follow the wizard through.

AppWizardX will generate a directory structure that will make more sense than the files the current AppWizard generates. Unfortunately I haven't gotten around to adding comments to the generated source files yet to offer direction on how to override behaviors and such, but at this point please just generate this first test app and verify that it works at a basic level.

I don't think you should add more tabs if the tabs don't relate directly with the entity for that form, although that can certainly be done but you've got to write code in the overridden method.

For instance, this line at the end of my FrmClients.afterInit() adds a page that I've defined to list the client's activity and report their current balance:

                self.PageFrame.appendPage(PagClientBalance, "Balance")


> 2.  I need to customise the search page to search on foreign keys with
> drop down menus.  The options in FieldSpecEditor seem limited.  How can
> I add custom fields to configure the search form (and also the entry
> form) to a greater degree

I'm working on giving user code a hook into the search options, so stay tuned on that. As far as the edit page goes, you can override that by changing your form code (located in ui/Frm*.py, where * is the name of the table) to something like (my example is with FrmClients):

class FrmClients(FrmBase):

        def initProperties(self):
                FrmClients.doDefault()
                self.NameBase = "frmClients"
                self.Caption = "Clients"


        def addEditPage(self, dataSource, title, pageClass=None):
                # If you have an overrided edit page, stick it in here:
                pageClass = self.Application.ui.PagEditClient
                FrmClients.doDefault(dataSource, title, pageClass)

I've just told Dabo to load my custom edit page, and I'm now required to create that edit page. This requires you getting your hands dirty and actually writing some code. Here is my PagEditClient class, located in ui/PagEditClient.py:


import dabo
from PagBase import PagBase
import baseControls


class PagEditClient(PagBase):

        def afterInit(self):
                lProps = {"Width": 150, "Alignment": "Right"}
                fProps = {"DataSource": "clients"}

                p = self.addObject(dabo.ui.dPanel, Name="panAddress", 
Sizer=dabo.ui.dSizer("v"))
                p.Sizer.appendSpacer(10)
                hs = dabo.ui.dSizer("h")
                hs.append(p.addObject(baseControls.LblBase, Caption="Attention (f, 
m, l):",
                                      **lProps))
                hs.append(p.addObject(baseControls.TxtBase, DataField="cfirst", 
Width=100,
                                      **fProps))
                hs.append(p.addObject(baseControls.TxtBase, 
DataField="cmiddle", Width=100,
                                      **fProps))
                hs.append(p.addObject(baseControls.TxtBase, DataField="clast", 
Width=130,
                                      **fProps))
                p.Sizer.append(hs)
                
                hs = dabo.ui.dSizer("h")
                hs.append(p.addObject(baseControls.LblBase, Caption="Company:", 
**lProps))
                hs.append(p.addObject(baseControls.TxtBase, 
DataField="ccompany",
                          Width=330, **fProps))
                p.Sizer.append(hs)

                hs = dabo.ui.dSizer("h")
                hs.append(p.addObject(baseControls.LblBase, Caption="Address:", 
**lProps))
                hs.append(p.addObject(baseControls.TxtBase, 
DataField="caddress1",
                          Width=330, **fProps))
                p.Sizer.append(hs)

                hs = dabo.ui.dSizer("h")
                hs.append(p.addObject(baseControls.LblBase, Caption="", 
**lProps))
                hs.append(p.addObject(baseControls.TxtBase, 
DataField="caddress2",
                          Width=330, **fProps))
                p.Sizer.append(hs)

                hs = dabo.ui.dSizer("h")
                hs.append(p.addObject(baseControls.LblBase, Caption="", 
**lProps))
                hs.append(p.addObject(baseControls.TxtBase, 
DataField="caddress3",
                          Width=330, **fProps))
                p.Sizer.append(hs)

                hs = dabo.ui.dSizer("h")
                hs.append(p.addObject(baseControls.LblBase, Caption="City, State, 
Zip:",
                          **lProps))
                hs.append(p.addObject(baseControls.TxtBase, DataField="ccity", 
Width=150,
                          **fProps))
                hs.append(p.addObject(baseControls.TxtBase, DataField="cstate", 
Width=55,
                          **fProps))
                hs.append(p.addObject(baseControls.TxtBase, DataField="czip", 
Width=125,
                          **fProps))
                p.Sizer.append(hs)

                hs = dabo.ui.dSizer("h")
                hs.append(p.addObject(baseControls.LblBase, Caption="Phone1, Phone2, 
Fax:",
                          **lProps))
                hs.append(p.addObject(baseControls.TxtBase, 
DataField="cphone1", Width=110,
                          **fProps))
                hs.append(p.addObject(baseControls.TxtBase, 
DataField="cphone2", Width=110,
                          **fProps))
                hs.append(p.addObject(baseControls.TxtBase, DataField="cfax", 
Width=110,
                          **fProps))
                p.Sizer.append(hs)

                hs = dabo.ui.dSizer("h")
                hs.append(p.addObject(baseControls.LblBase, Caption="email:", 
**lProps))
                hs.append(p.addObject(baseControls.TxtBase, DataField="cemail", 
Width=330,
                          **fProps))
                p.Sizer.append(hs)

                hs = dabo.ui.dSizer("h")
                hs.append(p.addObject(baseControls.LblBase, Caption="URL:", 
**lProps))
                hs.append1x(p.addObject(baseControls.TxtBase, DataField="curl", 
Width=330,
                            **fProps))
                p.Sizer.append(hs)

                self.Sizer.append(p)

                del(lProps["Width"])

                p = self.addObject(dabo.ui.dPanel, Name="panMiddle",
                                   Sizer=dabo.ui.dSizer("v"))
                p.Sizer.appendSpacer(10)
                hs = dabo.ui.dSizer("h")
                hs.appendSpacer(50)
                hs.append(p.addObject(baseControls.LblBase, Caption="Code:", 
Width=50,
                          **lProps))
                hs.append(p.addObject(baseControls.TxtBase, DataField="ccode", 
Width=50,
                          **fProps))
                hs.append(p.addObject(baseControls.LblBase,
                          Caption="Default Billing Rate:", Width=150, **lProps))
                hs.append(p.addObject(baseControls.TxtBase, DataField="nrate", 
Width=50,
                          **fProps))
                hs.append(p.addObject(baseControls.LblBase, Caption="Terms:", 
Width=50,
                          **lProps))
                hs.append(p.addObject(baseControls.TxtBase, DataField="cterms", 
Width=75,
                          **fProps))
                p.Sizer.append(hs)

                self.Sizer.append(p)

                p = self.addObject(dabo.ui.dPanel, Name="panBottom",
                                   Sizer=dabo.ui.dSizer("v"))
                p.Sizer.appendSpacer(10)
                hs = dabo.ui.dSizer("h")
                hs.append(p.addObject(baseControls.LblBase, Caption="Notes:", 
Width=100,
                          **lProps))
                hs.append(p.addObject(baseControls.EdtBase, Width=375, 
DataField="mnotes",
                          **fProps), "expand")
                p.Sizer.append1x(hs)

                self.Sizer.append1x(p)
                self.Sizer.appendSpacer(10)


Yuck! Some of the lines wrapped, so watch out for that. Basically, 95% of this code is boilerplate sizer-related stuff. It took about an hour for me to edit/test/repeat until I got the layout right. The layout the wizard outputs is acceptable for small tables and as a default, but for anything else you are going to have to do something like my above code to get a good layout. The basecontrols are just thin wrappers over the dabo base controls. Ignore them and just replace in your mind eg baseControls.LblBase -> dabo.ui.dLabel.

I don't mean to overwhelm you, but this is the level at which you currently must work in order to get effective with Dabo. This won't always be the case, but it is the case right now. Dabo as a framework and library is really 95% capable right now given wxPython and the databases we support. But as a RAD tool it has only begun to scratch the surface.


> 3.  Many of the reports I will need to produce involve joins from
> several tables.  For example, a report of each orditem with the total
> number of orders.  Where would such code go

Multi-table joins aren't a problem, that is a common need. What the runtime ReportWriter needs is a single dataset (denormalize your multiple tables into one dataset with repeated values in the proper order for consumption by the report writer), and a report format xml file (rfxml). The rfxml has sections for different report bands (pageHeader, pageFooter, detail, groupHeader, groupFooter...), report grouping definitions (what expression to group on), report variable definitions (running totals by group, for example), the page margins and orientation, etc. Each band can have any number of objects such as rectangles, lines, strings, and long strings. Each object has properties such as font, font size, rotation, background/foreground color.

For my invoices, I have a getInvoicesDataSet() function in my db layer that puts everything I need into the invoices dataset. Then, in my reports directory I have invoice.rfxml which specifies the layout of the invoice report. I coded both of these by hand, an investment of perhaps 8-12 tedious hours, mostly spent on edit/test/repeat of the invoice report format. The report actually gets run from a menu item Reports|Invoices, which pulls up a modal dialog with some selection criteria and a "Run Report" button.

The tedium of manually constructing the rfxml file will go away as soon as the ReportDesigner is working (a few months at least). The tedium of constructing the UI forms, pages, etc. will go away as soon as the UI Designer is working (probably a few months as well).

We really appreciate your thoughts and feedback, and hope Dabo can work for you.


> I really would like to use Dabo.  The benefits to Dabo would be an
> international (non-IT) company using Dabo as it's primary recording
> system.  I'm sure that would make for good press

I'll just come out and ask: would there be any opportunity for a contract with Ed and/or myself to get this implemented for you? You'd walk away with source code you could look at and tweak to your needs, and we'd walk away with needed financial support as well as a better Dabo.


--
Paul McNett
http://paulmcnett.com
http://dabodev.com


_______________________________________________
Post Messages to: [email protected]
Subscription Maintenance: http://leafe.com/mailman/listinfo/dabo-users

Reply via email to