PyGTK - polling GTK table for locations of widgets - python

I'm working on a Python application involving the use of a GTK table. The application requires that widgets of various sizes be added to a table dynamically. Because of this, I need to be able to ask the table what cells are in use (more accurately, NOT in use) so that I know where I can place a new widget without overlapping.
Based on the information in the reference manual (http://www.pygtk.org/docs/pygtk/) I have been unable to find a way to get that information directly from the table. The only other option I can think of is to create a map object that holds used cell information, and have it updated upon changes to the table.
Since I'm sure someone has dealt with this before me, and I would hope GTK would provide a better way, it seemed wise to ask around before trying to implement the map.
Help would be greatly appreciated.

This function should give you a set of the free cells in the table:
def free_cells(table):
free_cells = set([(x,y) for x in range(table.props.n_columns) for y in range(table.props.n_rows)])
def func(child):
(l,r,t,b) = table.child_get(child, 'left-attach','right-attach','top-attach','bottom-attach')
used_cells = set([(x,y) for x in range(l,r) for y in range(t,b)])
free_cells.difference_update(used_cells)
table.foreach(func)
return free_cells
It starts with a set of all the table cells, then iterates over the children of the table, removing the cells occupied by each child.

I'm the original poster, was logged into wrong account when posting question.
Anyway, this appears to be exactly what I'm looking for! Thanks Geoff!

Related

Filter options provided by QSqlRelationalDelegate/QSqlRelation acourding to some WHERE close

I have a QTableView populated by QSqlRelationalTableModel.
There is a column that references another table, so when I edit/create a row, this column's editor is QCombobox which gets its data from the related table. The problem is that I want to filter the data with some predefined WHERE close on the related table.
Example:
Tables:
Person:
id, name, job_id;
Job:
id, title, salary
What I want is something like
model.setRelation(3,QSqlRelation("Job", "id", "title", "WHERE salary > 50000"))
So that the QCombobox will have only Job titles with salaries > 5000.
I cannot use QSqlQueryModel as suggested in SO question - I still need users to be able to add new data or edit existing data.
It seems that someone managed to achieve this 10 years ago by tweaking the QT source code, but my C++ is bad so I could not figure it out quite well.
Possible solutions:
The first thing that comes to mind is to implement my own QSqlRelationalDelagate and populate QCombobox in the createEditor and set appropriate values in setModelData. I will try to do it myself and report the results back here. But it seems not very clean to me.
The best way would be to Extend the functionality of the QSqlRelation or QSqlRelationalTableModel but the documentation on it seems to be not very clear. So the real question is for experienced QT/PyQT developers: How do I solve the problem this way?
Update
So filtering out the contents of the QCombobox in the createEditor of the delegate works, but it requires a database query every time the editor is created which seems a bit off. And also it was quite a mess to handle new indexes after filtering. But I still wonder about the second way of approaching the problem.

Web2Py Multiple Smartgrids in a view

I am trying to build a view in web2py that has multiple smartgrid objects served from the same controller. It displays them absolutely fine, but whenever I try to create a new record on the second table it doesn't allow entry, it just seems to refresh the page. Also trying to search on the second table actually fills in the search field on the first table too, so there is obviously some confusion as to which smartgrid is which.
In my research I came across the multiple form technique using process to name each form, see below:
form1.process(formname='form1')
However, this methodology doesn't seem to work for smartgrid objects (as far as I can tell). I guess I could try to create my own new SQLFORM.grid, but it seems a shame that I can't make better use of the smartgrids, as they have everything I need already.
Any help appreciated.
As you have noted, you cannot have two grids on the same page in this manner, as the grid makes use of the URL to determine its current state. Instead of the iframe approach, though, you might consider putting each grid in an Ajax component. In the main view file:
{{=LOAD('default', 'grid1.load', ajax=True)}}
{{=LOAD('default', 'grid2.load', ajax=True)}}
Of course, you can also serve both grids from the same action by specifying a URL arg to differentiate them.
To allow the grid machinery to deal with generated URLs like
/app/default/grid1.load/view/record/1?_signature=88ce76119afc68bbb141fce098cbc2eaf39289e3
for a view of a single record,
you must identify grids uniquely.
So construct your grids with formname keyword. Example:
def manage_records():
q_record = (db.record.au==auth.user_id)
return dict(record = SQLFORM.grid(q_record, formname='records'))
def manage_reports():
q_report = (db.report.au==auth.user_id)
return dict(record = SQLFORM.grid(q_report, formname='reports'))
Just as Antony have pointed, you can use LOAD() functionality.
You can omit ajax=True, if you want forms will load with a main page.
In the view with two grids:
<h2>Reports</h2>
{{=LOAD('default', 'manage_reports.load')}}
<h2>Records</h2>
{{=LOAD('default', 'manage_records.load')}}

QAbstractTableModel and QComboBox together

I have a subclass of a QAbstractTableModel and I want to use QComboBox to display a dropbox for this table.
But by default it shows just the first column of my table, which is not what I want. I've tried setModelColumn to shows the column 1 instead of 0 but it did not work.
After having a look around in the internet, I've found 2 solutions:
Create another QAbstractListModel from the same data in the QAbstractTableModel
Use a QSortFilterProxyModel to hide other columns
Which is the best?
Thanks
Using setModelColumn should work. I would try to fix that. Perhaps you set the modelColumn at the wrong time, docs have this to say about it:
If set prior to populating the combo box, the pop-up view will not be affected and will show the first column (using this property's default value).
If this really doesn't work, and I'm quite sure it should, then use a QSortFilterProxyModel. This will be a lot less work and should be almost trivial.

How do I create a new data table in Orange?

I am using Orange (in Python) for some data mining tasks. More specifically, for clustering. Although I have gone through the tutorial and read most of the documentation, I still have a problem.
All the examples in docs and tutorials assume that I have a tab delimited table with data in it. However, there is nothing saying how one can go about creating a new table from scratch. For example, I want to create a table for word frequencies across different documents.
Maybe I am missing something so if anyone has any insight it'd be appreciated.
Thanks
George
EDIT:
This is how I create my table
#First construct the domain object (top row)
vars = []
for var in variables:
vars.append(Orange.data.variable.Continuous(str(var)))
domain = Orange.data.Domain(vars, classed) #The second argument indicated that the last attr must not be a class
#Add data rows assuming we have a matrix
t = Orange.data.Table(domain, matrix)
This took me hours to figure out. In python, do this:
Import Orange
List, Of, Column, Variables = [Orange.feature.Discrete(x) for x in ['What','Theyre','Called','AsStrings']]
Domain = Orange.data.Domain([List, Of, Column, Variables])
Table = Orange.data.Table(Domain)
Table.save('NewTable.tab')
I'd tell you what each bit of code does, but as of now I'm not really sure. It's funny that such a powerful toolkit should have such hard to understand documentation, but I suspect it's because it's entire user base has doctorates.
The documentation is indeed insufficient if you ask me. This may not be the answer to the question but it could be helpful to someone else. I tried for hours to create a Table using constructors and Domains and what not, just for an association rule mining task, and finally found out that the easiest way to create a table is simply to write your data to a file with the extension .tab or .basket and create a table from that.
Orange.data.Table("yourFile.basket")
Of course the structure of the file needs to be correct. See the provided example files located in the Orange package directory inside datasets/

Using custom role in QTreeView instead of DisplayRole

A simple question, (hopefully with a simple answer).
QTreeView will pass Qt.DisplayRole to the model's data function when fetching rows for display, by default.
But say I wanted to pass 'MyAwesomeTreeDisplayRole' instead of Qt.DisplayRole, what would I need to do?
I can't seem to find anything about where the view decides to use displayrole or how to override it.
Just before you ask why I want to do such awful things..
Basically, my QAbstractItemModel is intended to be usable both for a treeview (1 column) and a tableview (multiple columns, based on parent).
Using the same DisplayRole for both types of views doesn't really work, since then I'm forced to return the same data for both. This results in me only seeing the first column in the treeview when I want to return a concatenation of a couple of columns.
I think the simplest way would be to just use custom roles (TreeDisplayRole and TableDisplayRole).
Thanks in advance.
I don't know, how to do it in python, but you have to create your own delegate to render items data. Delegate is actually the object, that requests any data from indices and renders it
Note, that in common case QTreeView is able to show multiple columns, you should only have columnCount set incorrectly for top-level index
I've used QTreeView to view a simple table with many columns - it works well - you can adjust the column count by sending it the columnCountChanged signal. So I'm not sure you need to do what you are asking.
But I've used ItemDelegates too: use my_treeview.setItemDelegate() to point the treeview to your item delegate. If this subclasses QStyledItemDelegate then it doesn't need to do much work - it can mostly just pass it all through to super.
The user roles then are just agreed between your custom ItemDelegate and your ItemModel and can be anything you like as long as they are >= than QtCore.Qt.UserRole.
(Edit: Sorry, I put this in as a new answer but it's really just an elaboration on what Lol4t0 said - apart from the columnCountChanged thing)

Categories

Resources