accessing GUI widgets of one file in different classes pyqt5 [closed] - pyqt

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I'm a newbie how do I solve this?
My main question is I'm building a GUI application that has many widgets hence writing all those functions into a single file isn't a good practice hence while writing only I created 2 files I wrote half functionalities in one file and another half in another file (i thought we can connect files and everything will fine) so now I'm trying to make one of the main class and import other all into it but importing them alone isn't working so I'm confused how to do
my original GUI looks like this
tab 1
tab 2
each of these 2 tabs code is written in 2 separate files. and standalone code files workes file so now I want to add something in tab 1 file so tab 2 will also work fine.
A test GUI and code so someone can try to understand the problem more clearly
hence I made an example here
with 1 GUI and 2 dropdowns and 2 codes which work standalone for one dropdown
now my question is what are the changes to be done so i can run one file and import all other files info and run all functionality fully from only one file
My GUI (this is a sample made to test)
its code
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QComboBox" name="comboBox_select_number">
<property name="geometry">
<rect>
<x>80</x>
<y>240</y>
<width>311</width>
<height>41</height>
</rect>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<item>
<property name="text">
<string>Select number</string>
</property>
</item>
<item>
<property name="text">
<string>1</string>
</property>
</item>
<item>
<property name="text">
<string>2</string>
</property>
</item>
<item>
<property name="text">
<string>3</string>
</property>
</item>
</widget>
<widget class="QComboBox" name="comboBox_select_gender">
<property name="geometry">
<rect>
<x>410</x>
<y>240</y>
<width>311</width>
<height>41</height>
</rect>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<item>
<property name="text">
<string>Select gender</string>
</property>
</item>
<item>
<property name="text">
<string>Male</string>
</property>
</item>
<item>
<property name="text">
<string>Female</string>
</property>
</item>
</widget>
<widget class="QLabel" name="label_selected_number">
<property name="geometry">
<rect>
<x>80</x>
<y>195</y>
<width>311</width>
<height>31</height>
</rect>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>TextLabel</string>
</property>
</widget>
<widget class="QLabel" name="label_selected_gender">
<property name="geometry">
<rect>
<x>410</x>
<y>200</y>
<width>311</width>
<height>31</height>
</rect>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>21</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
I added 2 combo_boxes and accessing them from 2 different files
I want this class to be the parent/main class
File one code that I want to make as a parent class (for number dropdown)
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QMainWindow, QApplication, QPushButton, QTextEdit, QFileDialog
from PyQt5 import uic
import sys
class Mainn(QMainWindow):
def __init__(self):
super(Mainn, self).__init__()
uic.loadUi("lol.ui", self)
self.show()
self.comboBox_select_number.currentIndexChanged.connect(self.updatenumber)
def updatenumber(self):
number=self.comboBox_select_number.currentText()
self.label_selected_number.setText(number)
app = QApplication(sys.argv)
window = Mainn()
app.exec_()
2nd file code for(gender dropdown)
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QMainWindow, QApplication, QPushButton, QTextEdit, QFileDialog
from PyQt5 import uic
import sys
class UI(QMainWindow):
def __init__(self):
super(UI, self).__init__()
uic.loadUi("lol.ui", self)
self.show()
self.comboBox_select_gender.currentIndexChanged.connect(self.updategender)
def updategender(self):
gender=self.comboBox_select_gender.currentText()
self.label_selected_gender.setText(gender)
app = QApplication(sys.argv)
window = UI()
app.exec_()
I do know when I run them separately they do only their specific work now I want to combine them so if run the main file both combo box should work suggest me minimal changes of code to work on it.
i do know we can combine like this into a single file and run
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QMainWindow, QApplication, QPushButton, QTextEdit, QFileDialog
from PyQt5 import uic
import sys
class Mainn(QMainWindow):
def __init__(self):
super(Mainn, self).__init__()
uic.loadUi("lol.ui", self)
self.show()
self.comboBox_select_number.currentIndexChanged.connect(self.updatenumber)
self.comboBox_select_gender.currentIndexChanged.connect(self.updategender)
def updatenumber(self):
number=self.comboBox_select_number.currentText()
self.label_selected_number.setText(number)
def updategender(self):
gender=self.comboBox_select_gender.currentText()
self.label_selected_gender.setText(gender)
app = QApplication(sys.argv)
window = Mainn()
app.exec_()
and it works
so I want to get the same functionality with the 2 files by somehow linking them

Hi Finally found a solution
I do know this isn't a good code and it may be completely wrong but I'm getting my required output.
File 1 code
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QMainWindow, QApplication, QPushButton, QTextEdit, QFileDialog
from PyQt5 import uic
import sys
class Mainn(QMainWindow):
def __init__(self):
super(Mainn, self).__init__()
uic.loadUi("lol.ui", self)
self.comboBox_select_number.currentIndexChanged.connect(self.updatenumber)
def updatenumber(self):
number=self.comboBox_select_number.currentText()
self.label_selected_number.setText(number)
file 2 code
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QMainWindow, QApplication, QPushButton, QTextEdit, QFileDialog
from PyQt5 import uic
import sys
from main import Mainn
class UI(QMainWindow):
def __init__(self, parent = None):
super(UI, self).__init__(parent)
self.ui=Mainn()
self.ui.__init__()
self.ui.show()
self.ui.comboBox_select_gender.currentIndexChanged.connect(self.updategender)
def updategender(self):
gender=self.ui.comboBox_select_gender.currentText()
self.ui.label_selected_gender.setText(gender)
app = QApplication(sys.argv)
window = UI()
app.exec_()
now if i run file 2 it works as per my requirement
If still their are any improvements please let me know thank you

Related

Best practices for using QSplitter in pyqt5? Trying to add a movable separator to a project

A UI that I'm trying to create looks roughly like this:
Until now there's been no splitter, but now I want to put a movable splitter where the red line is and be able to drag it left or right.
So I used a QSplitter(using Qt Creator) and put it there ( where the red line is), but it doesn't work the way I want it; when I drag the splitter it doesn't 'slide' along with the mouse. Instead, it's like there are 3 options:
closing the menu side entirely ( and doing so badly; can't see the separator itself)
The 'normal' position (exactly as before dragging the separator)
Closing the content side entirely ( and doing that badly as well)
I'd love to provide more information but I don't really know what would be helpful. Please let me know what would be helpful.
Thanks.
UPDATE:
The code #bfris added here inspired me to create a mockup playground and try a bunch of things.
so I copied the content side and the menu side from my project to the playground, added a QSplitter and everything just worked great.
But then I tried to do the same in my project - and I saw the same behavior I described above .
So I played with my project a little more to investigate what could be the cause; I tried to leave the menu side (frame) empty - same behavior. Tried to leave the content side empty - and the QSplitter worked well(!).
So I brought the content back into my project and tried to change its' horizontal size policy to 'ignored' - and that worked too, but the proportions were waaay off; The menu side was initially bigger than the content side.
The interesting part is that at the playground I didn't have to change the size policy.
Any thoughts what might be the difference between the playground and the project? Or how to make the proportions right when horizontal size policy is 'ignored'?
I've not seen a QSeparator. QSplitters work very nicely and smoothly.
This is an example I worked up i Qt Designer. qsplitter_example.ui:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<property name="styleSheet">
<string notr="true">QWidget {
background-color: blue;
}
QLabel {
background-color: orange;
}</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>100</height>
</size>
</property>
<property name="font">
<font>
<family>Calibri</family>
<pointsize>24</pointsize>
</font>
</property>
<property name="text">
<string>Headline</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QSplitter" name="splitter">
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QLabel" name="label">
<property name="font">
<font>
<family>Calibri</family>
<pointsize>24</pointsize>
</font>
</property>
<property name="text">
<string>menu</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
<widget class="QLabel" name="label_2">
<property name="font">
<font>
<family>Calibri</family>
<pointsize>24</pointsize>
</font>
</property>
<property name="text">
<string>Content</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>26</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
After much trial and error (thanks to #bfris who inspired me to create a mockup playground) I have found what the issue was.
Quite annoyingly, it appears that I have misplaced the content (of, well, the content frame) into the wrong frame!
Now That I moved it back to the correct frame, all I needed was to set the content frame's horizontal size policy to 'ignored'.

Gtk4: How to specify rows and columns of a GtkGrid object within a GtkBuilder ui file

I would like to use a GtkBuilder ui file to declare a GtkGrid with 3 rows and 2 columns. The ui file should be usable with gtk4-rs (https://github.com/gtk-rs/gtk4-rs). Initially I used glade to get a first sketch of the ui file, but unfortunately gtk4-rs did fail to load it. Therefore I striped it down until I could start my app. How can I assign the elements into columns, so that gtk4-rs will still be able to load it?
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="3.4"/>
<object class="GtkApplicationWindow" id="window">
<child>
<object class="GtkGrid">
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Label1</property>
</object>
</child>
<child>
<object class="GtkButton" id="src_button">
<property name="label" translatable="yes">Source</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Label2</property>
</object>
</child>
<child>
<object class="GtkButton" id="trg_button">
<property name="label" translatable="yes">Target</property>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">Start</property>
<property name="receives-default">True</property>
</object>
</child>
</object>
</child>
</object>
</interface>
Where do I find the DTD for GtkGrind or other Gtk4 objects??
I don't know, did you found it out or not, but someone probably will come across to this post looking for the answer. Solution is to use <layout> inside child <object>. In your example it will be:
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="3.4"/>
<object class="GtkApplicationWindow" id="window">
<child>
<object class="GtkGrid">
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Label1</property>
<layout>
<property name="row">0</property>
<property name="column">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkButton" id="src_button">
<property name="label" translatable="yes">Source</property>
<layout>
<property name="row">0</property>
<property name="column">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Label2</property>
<layout>
<property name="row">1</property>
<property name="column">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkButton" id="trg_button">
<property name="label" translatable="yes">Target</property>
<layout>
<property name="row">1</property>
<property name="column">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">Start</property>
<property name="receives-default">True</property>
<layout>
<property name="row">3</property>
<property name="column">0</property>
</layout>
</object>
</child>
</object>
</child>
</object>
</interface>

Integrating Apache Cassandra with Apache Ignite

I'm trying to integrate Apache Ignite with Apache Cassandra(3.11.2) as I want to use Ignite to cache the data present in my already existing Cassandra database.
After going through the online resources, I've done the following till now:
Downloaded Apache Ignite.
Copied all the folders present in "libs/optional/" to "libs/"(I don't know which ones will be required for Cassandra).
Created 3 xmls in the config folder i.e. "cassandra-config.xml", "connection-settings.xml" and "persistance-settings.xml". Currently I'm using the same node(172.16.129.68) for both Cassandra and Ignite.
cassandra-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- Cassandra connection settings -->
<import resource="connection-settings.xml" />
<!-- Persistence settings for 'cache1' -->
<bean id="cache1_persistence_settings" class="org.apache.ignite.cache.store.cassandra.persistence.KeyValuePersistenceSettings">
<constructor-arg type="org.springframework.core.io.Resource" value="file:/home/cass/apache_ignite/apache-ignite-fabric-2.4.0-bin/config/persistance-settings.xml" />
</bean>
<!-- Ignite configuration -->
<bean id="ignite.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
<property name="cacheConfiguration">
<list>
<!-- Configuring persistence for "cache1" cache -->
<bean class="org.apache.ignite.configuration.CacheConfiguration">
<property name="name" value="cache1"/>
<property name="readThrough" value="true"/>
<property name="writeThrough" value="true"/>
<property name="writeBehindEnabled" value="true"/>
<property name="cacheStoreFactory">
<bean class="org.apache.ignite.cache.store.cassandra.CassandraCacheStoreFactory">
<property name="dataSourceBean" value="cassandraAdminDataSource"/>
<property name="persistenceSettingsBean" value="cache1_persistence_settings"/>
</bean>
</property>
</bean>
</list>
</property>
<!-- Explicitly configure TCP discovery SPI to provide list of initial nodes. -->
<property name="discoverySpi">
<bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
<property name="ipFinder">
<!--
Ignite provides several options for automatic discovery that can be used
instead os static IP based discovery. For information on all options refer
to our documentation: http://apacheignite.readme.io/docs/cluster-config
-->
<!-- Uncomment static IP finder to enable static-based discovery of initial nodes. -->
<!--<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder">-->
<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder">
<property name="addresses">
<list>
<!-- In distributed environment, replace with actual host IP address. -->
<value>172.16.129.68:47500..47509</value>
</list>
</property>
</bean>
</property>
</bean>
</property>
</bean>
connection-settings.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="loadBalancingPolicy" class="com.datastax.driver.core.policies.TokenAwarePolicy">
<constructor-arg type="com.datastax.driver.core.policies.LoadBalancingPolicy">
<bean class="com.datastax.driver.core.policies.RoundRobinPolicy"/>
</constructor-arg>
</bean>
<bean id="cassandraAdminDataSource" class="org.apache.ignite.cache.store.cassandra.datasource.DataSource">
<property name="port" value="9042"/>
<property name="contactPoints" value="172.16.129.68"/>
<property name="readConsistency" value="ONE"/>
<property name="writeConsistency" value="ONE"/>
<property name="loadBalancingPolicy" ref="loadBalancingPolicy"/>
</bean>
persistance-settings.xml
<persistence keyspace="test" table="epc_table">
<keyPersistence class="java.lang.String" strategy="PRIMITIVE" column="imsi"/>
<valuePersistence strategy="BLOB"/>
</persistence>
I run the following command to start Ignite from bin folder.
ignite.sh ../config/cassandra-config.xml
Now, I want to take a look at the cassandra table via sqlline. I've tried the following:
./sqlline.sh -u jdbc:cassandra://172.16.129.68:9042/test //(test is the name of the keyspace)
I get the following output:
No known driver to handle "jdbc:cassandra://172.16.129.68:9042/test". Searching for known drivers...
java.lang.NullPointerException
sqlline version 1.3.0
0: jdbc:cassandra://172.16.129.68:9042/test>
I've also tried:
./sqlline.sh -u jdbc:ignite:thin://172.16.129.68
but when I use "!tables", I'm not able to see any table.
What exactly has been missing? How to access/modify the tables present in Cassandra using sqlline?
Operating System: RHEL 6.5
Apache Ignite is a key-value database and there are no tables created by default that you are able to view with JDBC connector. CacheStore is a way to integrate Ignite with external DB or any other storage, and it loads data as a key-value pair.
In your config you said Ignite that you want to store and load entries in/from Cassandra, but still Ignite doesn't know entries structure (BTW Ignite really doesn't care what objects were putted into it).
To be able to list tables and do queries on it, you need to create tables. For that you need to have ignite-indexing in /lib directory and set QueryEntity or indexed types if you have annotated POJOs. Here is example of such configuration:
<bean class="org.apache.ignite.configuration.CacheConfiguration">
<property name="name" value="mycache"/>
<!-- Configure query entities -->
<property name="queryEntities">
<list>
<bean class="org.apache.ignite.cache.QueryEntity">
<property name="keyType" value="java.lang.Long"/>
<property name="valueType" value="org.apache.ignite.examples.Person"/>
<property name="fields">
<map>
<entry key="id" value="java.lang.Long"/>
<entry key="orgId" value="java.lang.Long"/>
<entry key="firstName" value="java.lang.String"/>
<entry key="lastName" value="java.lang.String"/>
<entry key="resume" value="java.lang.String"/>
<entry key="salary" value="java.lang.Double"/>
</map>
</property>
<property name="indexes">
<list>
<bean class="org.apache.ignite.cache.QueryIndex">
<constructor-arg value="id"/>
</bean>
<bean class="org.apache.ignite.cache.QueryIndex">
<constructor-arg value="orgId"/>
</bean>
<bean class="org.apache.ignite.cache.QueryIndex">
<constructor-arg value="salary"/>
</bean>
</list>
</property>
</bean>
</list>
</property>
If you configure that, you'll get an ability to enlist and query that tables over SQLine. (Please note, that you cannot query data that are not loaded into Ignite. To load them, you may use IgniteCache.get() with enabled readThrough option or IgniteCache.loadCache() to load everything from Cassandra table).
To query Cassandra with JDBC, you need a JDBC driver for it, try, for example DBSchema.

pyuic4 generates wrong layout?

pyuic4 seems to generate a wrong layout based on a .ui file from Qt Designer. The UI file is here:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>348</width>
<height>267</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item alignment="Qt::AlignTop">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>25</height>
</size>
</property>
<property name="text">
<string><html><head/><body><p align="center"><span style=" font-size:14pt;">Some Text</span></p></body></html></string>
</property>
</widget>
</item>
<item alignment="Qt::AlignTop">
<widget class="Line" name="line_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item alignment="Qt::AlignBottom">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item alignment="Qt::AlignBottom">
<widget class="QPushButton" name="btn_customize">
<property name="text">
<string>Customize</string>
</property>
</widget>
</item>
<item alignment="Qt::AlignBottom">
<widget class="QPushButton" name="btn_done">
<property name="text">
<string>OK</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
In this layout, I'm trying to align a pair of buttons with the bottom of the dialog window and some text with the top. Running pyuic4 test.ui --preview shows all objects aligned to the center horizontally, instead of to the top and bottom (and displaying this dialog from the actual python program shows the same results). By comparison, pyuic5 test.ui --preview seems to be more along the lines of what I wanted to get.
If it helps, my version of pyuic4 is 4.11.4 and I'm on Ubuntu 16.04.
Any ideas? Am I doing something wrong? Or is there perhaps a newer pyuic4 out there?
There was bug in pyuic that affected the handling of alignment in layouts. This was fixed in PyQt-5.5, which was released on the 17th July 2015. However, PyQt-4.11.4 (which is the current version) was released on the 11th June 2015 - so the fix has not been included, yet. The current development snapshot for PyQt-4.12 does includes the fix, though.
But I don't think this will really fix the issue you have. What you need to do instead is use expanding spacers. Here's how to do this using your example ui file:
Click on the horizontal button layout, and then click Break Layout (this will remove all the current layouts).
Ctrl+click the two buttons, and then click Layout Horizontally.
Click on the Dialog, and then click Layout Vertically.
Drag and drop a Vertical Spacer between the two Line widgets
Giving you this:
If you want to have some other widgets in the central area, you may need to add expanding vertical spacers above and/or below them to get the same results. Then again, if you put something like a text-box or list-widget in there, it should automatically expand to fill the available space - in which case, there wouldn't be any need for any spacers (or layout alignments).

Can't use a glade xml file with haskell

I'm not sure if I should say hi or not, being this my first post here.
Anyway, I am following the glade tutorial from the gtk2hs website. The code compiled properly but when I try to execute it I get this error.
(hellogtk2hs:8670): libglade-WARNING **: Expected <glade-interface>. Got <interface>.
(hellogtk2hs:8670): libglade-WARNING **: did not finish in PARSER_FINISH state
hellogtk2hs: user error (Pattern match failure in do expression at HelloGtk2Hs.hs:8:8-15)
This is my glade file.
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<child>
<object class="GtkBox" id="box1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Write your name here: </property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="entry1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">●</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkButton" id="button1">
<property name="label">gtk-apply</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button2">
<property name="label">gtk-close</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
The glade file is in the same directory as my source code. The source code is an exact copy from the one in the tutorial. I have never worked with glade before, so I have no idea of whats going wrong.
I had to downgrade ghc from 7.6 to 7.4.2. I'm using glade 3.14.1, all other packages were installed via cabal so they are on their current version.
If I switch interface with glade-interface, at the beginning and at the end it still complains.
(hellogtk2hs:9636): libglade-WARNING **: Unexpected element <object> inside <glade-interface>.
hellogtk2hs: user error (glade.xmlGetWidget: no object named "window1" in the glade file)
And if change all object tags with widget I get this
(hellogtk2hs:9668): GLib-GObject-ERROR **: cannot create instance of abstract (non-instantiatable) type `GtkBox'
`trap' para punto de parada/seguimiento
I get less errors by doing this but it still does not work.
The problem was that gtk2hs does not support gtk3, and the file I was creating was for gtk3.
Glade can generate either a libglade file or gtkbuilder file. Both are xml files, and the main difference between them is that the first starts with <glade-interface> and the later starts with <interface>. Also in gtkbuilder files the <object> tag is used instead of the <widget> tag.
The Graphics.UI.Gtk.Glade package makes use of the libglade files, and the problem is that these are obsolete and deprecated.
At the Glade download page there are two versions available. The newer of them generates gtkbuilders meant to be used with gtk3, but since gtk2hs does not support gtk3, you'll have to download version 3.8, which generates both libglade and gtkbuilder files for gtk2.
The best thing to do is to stop using libglade files and use the gtkbuilder files instead. To do this you must import Graphics.UI.Gtk.Builder instead of Graphics.UI.Gtk.Glade
I found this tutorial which makes use of gtkbuilder instead of libglade.
This program creates a window with a button, and every time you click the button you'll get a "hello world" on your terminal until the window is closed.
import Graphics.UI.Gtk
import Graphics.UI.Gtk.Builder
main = do
initGUI
builder <- builderNew
builderAddFromFile builder "windowbuilder.glade"
mainWindow <- builderGetObject builder castToWindow "main_window"
onDestroy mainWindow mainQuit
helloWorldButton <- builderGetObject builder castToButton "hello_world_button"
onClicked helloWorldButton (putStrLn "Hello, World!")
widgetShowAll mainWindow
mainGUI
This is pulling the gui from the windowbuilder.glade file. I created that file using glade-3. Here it is.
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="2.24"/>
<!-- interface-naming-policy project-wide -->
<object class="GtkWindow" id="main_window">
<property name="width_request">210</property>
<property name="can_focus">False</property>
<property name="title" translatable="yes">This is a window</property>
<property name="resizable">False</property>
<child>
<object class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Click the button!!</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="hello_world_button">
<property name="label">gtk-ok</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="border_width">7</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="padding">5</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
Another good reason to switch to gtkbuilder files is that the haskell glade package won't compile with ghc >= 7.6.

Resources