SQLAlchemy Date Problem

to skin the cat sqlite3 completely :rofl:

typeof(X)

The typeof(X) function returns a string that indicates the datatype of the expression X: “null”, “integer”, “real”, “text”, or “blob”.

# from sqlite3 test
import sqlite3 as sqlite
from datetime import date

class DateTimeTests():
    def setUp(self):
        self.con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_DECLTYPES)
        self.cur = self.con.cursor()
        self.cur.execute("create table test(d date, ts timestamp)")

    def tearDown(self):
        self.cur.close()
        self.con.close()

    def test_sqlite_date(self):
        d = date(2004, 2, 14)
        print(f'{d=} {type(d)=}')
        self.cur.execute("insert into test(d) values (?)", (d,))
        self.cur.execute("select d, typeof(d) from test")
        d2, sqltype = self.cur.fetchone()
        print(f'{d2=} {type(d2)=} {sqltype=}')
        print(f'{(d is d2)=} {(d == d2)=}')

dtt = DateTimeTests()
dtt.setUp()
dtt.test_sqlite_date()
dtt.tearDown()

if you start off with the wx.DateTime object it’s more efficient to store the ISO format right away, saves the work of the dbapi2 (unless you want to do calculations after reading) :globe_with_meridians:

# from sqlite3 test
import sqlite3 as sqlite
from wx import DateTime

class DateTimeTests():
    def setUp(self):
        self.con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_DECLTYPES)
        self.cur = self.con.cursor()
        self.cur.execute("create table test(d, ts timestamp)")

    def tearDown(self):
        self.cur.close()
        self.con.close()

    def test_sqlite_date(self):
        d = DateTime(14, DateTime.Feb, 2004).FormatISODate()
        print(f'{d=} {type(d)=}')
        self.cur.execute("insert into test(d) values (?)", (d,))
        self.cur.execute("select d, typeof(d) from test")
        d2, sqltype = self.cur.fetchone()
        print(f'{d2=} {type(d2)=} {sqltype=}')
        print(f'{(d is d2)=} {(d == d2)=}')

dtt = DateTimeTests()
dtt.setUp()
dtt.test_sqlite_date()
dtt.tearDown()


Still stuck. Not a coding error per se, I’m struggling with sizers. Just when I think I get it I’m missing something. The only issue now is to expand the notebook fully into the panel. However the panel does not fill the frame completely. NO idea why. I’m hoping the diagram helps if you can read it. Notice that the panel sizer is set to notebook_sizer. This was the only way so far that I could get the notebook and buttons to appear in the notebook thus in the panel.
I want the buttons to appear at the bottom of he panel and the ovl to expand to the tops of the button sizer. The space above in the panel needs to be filled with notebook. The color coding is to hopefully display the borders of the objects.
Any thoughts would be appreciated.

@da-dada

Comp-1 to comp-4 I remember them well.
Back when disc space was frighteningly expensive and you had to worry about the size of each record and aligning on word boundaries. Bytes? We worried about nibbles!

Tell that to the kids today and they won’t believe yer! :wink:

they still nibble but on what seems to have changed slightly
nevertheless I think the world is more resilient than some try to convince us (starting from the very early days) :innocent:

@mfones

I see the example I mentioned the other day wasn’t enlightening (again, horse hockey or ?)
so let’s try it less juicy (or more alchemistic ?)
there would usually be a main sizer for a GUI page (Frame) constituting the graphical concept (without concept :cold_sweat:) and sort of inside all the controls are placed (of course wrapped by an appropriate sizer to make it fill the space)
luckily there are only a few of them, just like the data types of sqlite, and the number of parameters are very small and almost identical
play around with them & enjoy how nice they do their duty :cowboy_hat_face:

@da-dada I don’t understand your first sentence. Actually a lot of your expressions don’t translate. What is your native language? That aside…

I’m almost there, there are so many combinations with sizers it’s a chore to keep track of them.
I’m trying to get three elements into a single notebook tab. The search, Olv and CRUD.

With Notebooks can you confirm that a panel needs to be created or can the notebooks parent be self?
Here’s what I have currently

panel = wx.Panel(self)

The notebook addition, please confirm is self or panel needs to used here, or does it matter as long as your consistant?

notebook = wx.Notebook(self, style=wx.NB_TOP)
notebook_sizer = wx.BoxSizer(wx.HORIZONTAL)
notebook_sizer.Add(notebook, 1, wx.ALL | wx.EXPAND , 5)

Had to use this to get the notebook visible and I can’t explain why. Any idea?

panel.SetSizer(notebook_sizer)

I have sizers for all three, with CRUD buttons grouped into a single sizer.

main_sizer = wx.BoxSizer(wx.VERTICAL)
search_sizer = wx.BoxSizer(wx.HORIZONTAL)
btn_sizer = wx.BoxSizer(wx.HORIZONTAL)

Creating the tab’s

tabOne = wx.Panel(notebook)
notebook.AddPage(tabOne, 'Ledger')
tabTwo = wx.Panel(notebook)
notebook.AddPage(tabTwo, 'Budget')

olv_sizer

olv_sizer = wx.BoxSizer(wx.HORIZONTAL)
olv_sizer.Add(self.ledger_results_olv, 1, wx.ALL | wx.EXPAND, 5)

One of the CRUD buttons, they just repeat the same format and added to btn_sizer

btn_sizer = wx.BoxSizer(wx.HORIZONTAL)
add_record_btn = wx.Button(tabOne, label="Add")
add_record_btn.Bind(wx.EVT_BUTTON, self.add_record)
btn_sizer.Add(add_record_btn, 0, wx.ALL, 5)

Now the main sizer.

main_sizer = wx.BoxSizer(wx.VERTICAL)
main_sizer.Add(search_sizer, 1, wx.ALL | wx.EXPAND, 1)
main_sizer.Add(olv_sizer, 1, wx.ALL | wx.EXPAND, 1)
main_sizer.Add(btn_sizer, 1, wx.ALL | wx.ALIGN_CENTER_HORIZONTAL, 1)
main_sizer.Add(panel, 0, wx.ALL | wx.EXPAND, 5)
self.SetSizer(main_sizer)

Wondering if something is obviously wrong and I’m not seeing it. This is such a rabbits hole now. I think I’m confusing things. The order of main_sizer is critical. If I comment out the Add panel in main_sizer there’s no display. Here’s what I have so far.


I think that the order is incorrect but I just can’t see it. The coloring is just for reference. Blue is the tab, pink is the panel and the dark yellow is the notebook.
Anyone see anything obviously wrong? Olv is not displaying. Set to vertically stretchable (1) using a Horizontal BoxSizer, but main_sizer is a Vertical BoxSizer. Is there a conflict there? I’ve tried both.
What am I missing?

I find that wxGlade is very useful for designing the layout of a UI. It allows you to easily test how the UI responds to resizing of a frame or dialog.

I have attempted to create a similar layout to what you show. wxGlade does not have direct support for ObjectListView controls, so for simplicity I have substituted a ListCtrl as it has a similar appearance.

Here is the code it generates:

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
#
# generated by wxGlade 1.0.5 on Thu Apr 13 08:58:42 2023
#

import wx

# begin wxGlade: dependencies
# end wxGlade

# begin wxGlade: extracode
# end wxGlade


class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        # begin wxGlade: MyFrame.__init__
        kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.SetSize((750, 550))
        self.SetTitle("frame")

        # Menu Bar
        self.frame_menubar = wx.MenuBar()
        wxglade_tmp_menu = wx.Menu()
        wxglade_tmp_menu.Append(wx.ID_ANY, "Exit", "")
        self.frame_menubar.Append(wxglade_tmp_menu, "File")
        self.SetMenuBar(self.frame_menubar)
        # Menu Bar end

        self.frame_statusbar = self.CreateStatusBar(1)
        self.frame_statusbar.SetStatusWidths([-1])
        # statusbar fields
        frame_statusbar_fields = ["frame_statusbar"]
        for i in range(len(frame_statusbar_fields)):
            self.frame_statusbar.SetStatusText(frame_statusbar_fields[i], i)

        self.main_panel = wx.Panel(self, wx.ID_ANY)

        main_sizer = wx.BoxSizer(wx.VERTICAL)

        self.notebook = wx.Notebook(self.main_panel, wx.ID_ANY)
        main_sizer.Add(self.notebook, 1, wx.EXPAND, 0)

        self.ledger_pane = wx.Panel(self.notebook, wx.ID_ANY)
        self.notebook.AddPage(self.ledger_pane, "Ledger")

        ledger_main_sizer = wx.BoxSizer(wx.VERTICAL)

        ledger_search_sizer = wx.BoxSizer(wx.HORIZONTAL)
        ledger_main_sizer.Add(ledger_search_sizer, 0, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, 4)

        ledger_search_label = wx.StaticText(self.ledger_pane, wx.ID_ANY, "Search By:")
        ledger_search_sizer.Add(ledger_search_label, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 2)

        self.ledger_search_combo_box = wx.ComboBox(self.ledger_pane, wx.ID_ANY, choices=[], style=wx.CB_DROPDOWN)
        ledger_search_sizer.Add(self.ledger_search_combo_box, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 4)

        self.ledger_search_text_ctrl = wx.TextCtrl(self.ledger_pane, wx.ID_ANY, "")
        ledger_search_sizer.Add(self.ledger_search_text_ctrl, 0, wx.ALIGN_CENTER_VERTICAL, 0)

        self.ledger_list_ctrl = wx.ListCtrl(self.ledger_pane, wx.ID_ANY, style=wx.LC_HRULES | wx.LC_REPORT | wx.LC_VRULES)
        self.ledger_list_ctrl.AppendColumn("A", format=wx.LIST_FORMAT_LEFT, width=-1)
        self.ledger_list_ctrl.AppendColumn("B", format=wx.LIST_FORMAT_LEFT, width=-1)
        self.ledger_list_ctrl.AppendColumn("C", format=wx.LIST_FORMAT_LEFT, width=-1)
        ledger_main_sizer.Add(self.ledger_list_ctrl, 1, wx.ALL | wx.EXPAND, 4)

        ledger_button_sizer = wx.BoxSizer(wx.HORIZONTAL)
        ledger_main_sizer.Add(ledger_button_sizer, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.BOTTOM | wx.TOP, 4)

        self.ledger_add_button = wx.Button(self.ledger_pane, wx.ID_ANY, "Add")
        ledger_button_sizer.Add(self.ledger_add_button, 0, wx.RIGHT, 8)

        self.ledger_edit_button = wx.Button(self.ledger_pane, wx.ID_ANY, "Edit")
        ledger_button_sizer.Add(self.ledger_edit_button, 0, wx.RIGHT, 8)

        self.ledger_delete_button = wx.Button(self.ledger_pane, wx.ID_ANY, "Delete")
        ledger_button_sizer.Add(self.ledger_delete_button, 0, wx.RIGHT, 8)

        self.ledger_show_all_button = wx.Button(self.ledger_pane, wx.ID_ANY, "Show All")
        ledger_button_sizer.Add(self.ledger_show_all_button, 0, 0, 0)

        self.ledger_pane.SetSizer(ledger_main_sizer)

        self.main_panel.SetSizer(main_sizer)

        self.Layout()
        # end wxGlade

# end of class MyFrame

class MyApp(wx.App):
    def OnInit(self):
        self.frame = MyFrame(None, wx.ID_ANY, "")
        self.SetTopWindow(self.frame)
        self.frame.Show()
        return True

# end of class MyApp

if __name__ == "__main__":
    app = MyApp(0)
    app.MainLoop()

For the parent/child hierarchy:
The Frame is the parent of the main Panel.
The main Panel is the parent of the Notebook.
The Notebook is the parent of the Panels that comprise its panes/pages.
Each pane is the parent of all the controls it contains.

When adding an item or sizer to a vertical BoxSizer, the proportion argument specifies how the much that item will be stretched vertically. In my example only the ListCtrl needs to be stretched vertically, so its proportion argument is set to one. The search sizer and button sizer do not need to stretch vertically, so their proportion arguments are set to zero.

I hope you can adapt ideas from this example to your design.

Tested using Python 3.10.6 + wxPython 4.2.0 gtk3 (phoenix) wxWidgets 3.2.0 on Linux Mint 21.1

1 Like

Copy and pasted the code and to my delight it’s exactly what I was hoping to accomplish. I’ll need some time to compare your code to mine. I suspect my problem is with the parent/child hierarchy in part. I’ll have a look at wxGlade. Thanks for your extra effort on my question. This has been really frustrating. Armed with this information I can hopefully get closer to the answer. I really appreciate this.
Can you tell me a little bit about the programming work you do? Do you do this for a living? Very impressive to me that you are able to decipher what I was struggling with and provide working code.
If direct messaging is more suitable, feel free to message me directly. Not sure how this works on this platform. Sticking to the forum is ok too.

Best regards.

I started doing software development while working for the UK Met Office. In 1996 I moved to the UK division of a US owned multinational IT company which was later bought by another US owned multinational IT company. That work was initially in C and Motif, but I started specialising in Python programming in 2000. I retired from work in 2014, but have continued to develop a number of my own applications purely for personal use and also to try to keep my brain active.

The retirement picture is getting clearer for me. I can retire now but unless I win a lottery, I’ll hold off for another 5 years. I work in electrical utility Engineering in Canada. Love to program for the same reason you mentioned, keeping the brain active. But not my core function. Hoping to have this project to keep adding features to. I am hoping to use it to manage the financials of a hockey team that I manage in my spare time. Currently using way too many spreadsheets that are prone to error. Moving from a spreadsheet concept to a database seemed like a logical step.
Your experience is valuable. Love to touch base with you offline if you can spare some time.

@mfones sorry for my untranslatables (my mother never listened :unamused:)

I can assure you that is a value in itself and every professional accountant will hug you for it (in Europe there seems to be much less of this spreadsheet madness), but a very big hurdle is translating historically grown spreadsheets into a somewhat correct relational database
the Gui afterwards is less problematic unless the faults of the base penetrate :sweat_smile:

@da-data no worries on the translation. What is your native language?

unlike @RichardT I started off with ALGOL & punched card (it was compulsory :rage: & I was interested in philosophy)

What is your native language?

After time spent learning wxGlade, creating the GUI again, success! With one small problem …


So a couple of details: panel is defined in the frame class, however panel is again defined in the class that has the majority of the GUI. That is the “guts” of the display, everything inside panel as it were. The pink box comes from this:

panel = wx.Panel(self)
panel_sizer = wx.BoxSizer(wx.VERTICAL
panel.SetBackgroundColour((175, 58, 148)) # OneNote Pink

I’ve tied to locate a sizer that is not fully expanded, nothing. Maybe an accumulation of margins? I’ve used 5 for all my spacers. Looks like the square might be 20 or 25. I believe the grey color in the back is the frame. So I gave the frame the OneNote Pink background. Still the same problem. The corner of the box encroaches into the Ledger tab.
Not sure it this helps but here are the last sizer calls. There is no tabTwo sizer.

tabOne.SetSizer(tabOne_sizer)
self.SetSizer(panel_sizer)
self.Layout()
self.Centre()

Any thoughts?

My first programming course in 1976 was for FORTRAN using punched cards. However, my employers then decided I should become a weather forecaster. Fortunately by the time I did eventually switch to IT work, the technology had advanced significantly.

I had something similar to this once when I used a wx.StaticBoxSizer with its label set to an empty string, instead of a plain wx.BoxSizer.

However, if that is not the case, could you please upload the .wxg file and I will take a look at it?

Note: if you use the forum’s Upload option instead of pasting the file, you will need to zip the file first as .wxg is not one of the accepted file types.

No wx.StaticBoxSizers in the project. There is one in the wxGlade layout but not the project.wxAccMan-master.zip (635.2 KB)
The entire project is in the zip. There is a folder wxGlade with the wxGlade layout. The final version in the srcreen capture is wxAccManGlade.py

@da-dada

I spent many a wet afternoon punching paper tape loops, by hand, for a Messer Griesheim cutting machine and punching cards, by hand, on a tiny machine like a manual typewriter.
Somewhere, I still have the paper tape punching widget. It’s about the size of a matchbox.
Ah, the bad old days, thank goodness we can look back on them! :wink:

GOSUB 200