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

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'.

Related

How to set expiry policy for ignite Cache [Inserting data using SPARK Dataframe]

I am trying to set Expiry Policy using xml config file:
<?xml version="1.0" encoding="UTF-8"?>
<!--
Ignite configuration with all defaults and enabled p2p deployment and enabled events.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<bean abstract="true" id="ignite.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
<!-- Set to true to enable distributed class loading for examples, default is false. -->
<property name="peerClassLoadingEnabled" value="true"/>
<!-- Enable task execution events for examples. -->
<property name="includeEventTypes">
<list>
<!--Task execution events-->
<util:constant static-field="org.apache.ignite.events.EventType.EVT_TASK_STARTED"/>
<util:constant static-field="org.apache.ignite.events.EventType.EVT_TASK_FINISHED"/>
<util:constant static-field="org.apache.ignite.events.EventType.EVT_TASK_FAILED"/>
<util:constant static-field="org.apache.ignite.events.EventType.EVT_TASK_TIMEDOUT"/>
<util:constant static-field="org.apache.ignite.events.EventType.EVT_TASK_SESSION_ATTR_SET"/>
<util:constant static-field="org.apache.ignite.events.EventType.EVT_TASK_REDUCED"/>
<!--Cache events-->
<util:constant static-field="org.apache.ignite.events.EventType.EVT_CACHE_OBJECT_PUT"/>
<util:constant static-field="org.apache.ignite.events.EventType.EVT_CACHE_OBJECT_READ"/>
<util:constant static-field="org.apache.ignite.events.EventType.EVT_CACHE_OBJECT_REMOVED"/>
</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>127.0.0.1:47500..47509</value>
</list>
</property>
</bean>
</property>
</bean>
</property>
</bean>
<bean class="org.apache.ignite.configuration.CacheConfiguration">
<property name="setExpiryPolicyFactory" >
<bean class="javax.cache.expiry.CreatedExpiryPolicy">
<!---- Remove all data after 10 Seconds---->
<property name="expiryDuration" value="10000"/>
</bean>
</property>
<property name="eagerTtl" value="true"/>
</bean>
I am a bit new for Ignite. I walk through documentation but unable to find. Is any way to setExpiryPolicy into XMl?
Any help would be appreciated!
That requires a bit of Spring XML magic because there is no easy-to-use factory class for the CreatedExpiryPolicy (i.e. no CreatedExpiryPolicyFactory that you can just instantiate like a normal bean), but there is the CreatedExpiryPolicy::factoryOf that can be passed as factory-method:
<property name="expiryPolicyFactory">
<bean class="javax.cache.expiry.CreatedExpiryPolicy" factory-method="factoryOf">
<constructor-arg>
<bean class="javax.cache.expiry.Duration">
<constructor-arg value="SECONDS"/>
<constructor-arg value="10"/>
</bean>
</constructor-arg>
</bean>
</property>
Apache Ignite doesn`t support expiry policies and TTL for SQL tables.
An alternative would be to create cache with dynamically generated names based on desired time window.
For example you could append hour of the day if you need it hourly:
MY_CACHE_00
MY_CACHE_01
MY_CACHE_02
etc...
MY_CACHE_23
Then make your software write/read to the latest hour CACHE, and clear the oldest.

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.

Need help on starting the Ignite cache in 2 node cluster

I am novice in Ignite and trying to utilize Ignite to setup in-memory cache. I did some basic configuration and started the Ignite based pluggable persistence work on single node. Now, I am planning to test the performance on 2 node cluster and setting up the ignite configuration as per below:
<?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="countryCacheStoreFactory" class="javax.cache.configuration.FactoryBuilder" factory-method="factoryOf">
<constructor-arg><value>com.xyz.exploreignite.cache.CustomCacheStore</value></constructor-arg>
</bean>
<bean id="stateCacheStoreFactory" class="javax.cache.configuration.FactoryBuilder" factory-method="factoryOf">
<constructor-arg><value>com.xyz.exploreignite.cache.CustomStateCacheStore</value></constructor-arg>
</bean>
<bean id="ignite.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
<property name="peerClassLoadingEnabled" value="false"/>
<property name="clientMode" value="true"/>
<property name="gridName" value="clusterGrid"/>
<property name="cacheConfiguration">
<list>
<!-- Partitioned cache example configuration (Atomic mode). -->
<bean class="org.apache.ignite.configuration.CacheConfiguration">
<property name="atomicityMode" value="ATOMIC"/>
<property name="backups" value="1"/>
<property name="name" value="customCountryCache"/>
<property name="readThrough" value="true"/>
<property name="writeThrough" value="true"/>
<property name="cacheMode" value="PARTITIONED"/>
<property name="writeBehindEnabled" value="true"/>
<property name="copyOnRead" value="true"/>
<property name="memoryMode" value="OFFHEAP_TIERED"/>
<property name="atomicWriteOrderMode" value="PRIMARY"/>
<property name="indexedTypes" >
<list>
<value>java.lang.Integer</value>
<value>com.xyz.exploreignite.pojo.Country</value>
</list>
</property>
<!-- Cache store. -->
<property name="cacheStoreFactory" ref="countryCacheStoreFactory"/>
</bean>
<bean class="org.apache.ignite.configuration.CacheConfiguration">
<property name="atomicityMode" value="ATOMIC"/>
<property name="backups" value="1"/>
<property name="name" value="customStateCache"/>
<property name="readThrough" value="true"/>
<property name="writeThrough" value="true"/>
<property name="cacheMode" value="PARTITIONED"/>
<property name="writeBehindEnabled" value="true"/>
<property name="copyOnRead" value="true"/>
<property name="memoryMode" value="OFFHEAP_TIERED"/>
<property name="atomicWriteOrderMode" value="PRIMARY"/>
<property name="indexedTypes" >
<list>
<value>java.lang.Integer</value>
<value>com.xyz.exploreignite.pojo.State</value>
</list>
</property>
<!-- Cache store. -->
<property name="cacheStoreFactory" ref="stateCacheStoreFactory"/>
</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>
<value>127.0.0.1:47500..47509</value>
<value>172.26.49.1:47500..47509</value>
<!-- In distributed environment, replace with actual host IP address. -->
<value>172.26.49.2:47500..47509</value>
</list>
</property>
</bean>
</property>
</bean>
</property>
</bean>
Now, while starting ignite with "bin/ignite.sh " on both the nodes it shows failed to connect to server. While running only "bin/ignite.sh" in parallel to above one, both the individual ignite config instance starts in standalone mode with only 1 client. I need to have both of them utilizing the shared instance. Please suggest possible issues in my deployment/execution.
Try to remove <value>127.0.0.1:47500..47509</value> line from the discovery configuration. It doesn't make much for a distributed cluster.
That configuration is in <property name="clientMode" value="true"/> You need to have at least one node set to <property name="clientMode" value="false"/> or else your clients won't have any server nodes to connect to.

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