After spending a long time searching for an answer, I hope someone can help me with this problem. I'm trying to use gtkmm (version 3.14.0) and glade (version 3.18.3) on a Fedora 21 system to create a Gtk::TreeView/Gtk::ListStore with many small images. I can easily place stock icons in the list, but adding Gdk::Pixbuf objects seems to go wrong. No error or warning messages are shown, but the Gdk::Pixbuf image is not shown.
To show the problem, I've created a minimal working example (the code of the program and the glade file included at the end). Running this program should open a small window with the Gtk::TreeView with two "gtk-apply" icons. In the first column should be the icon added as Gdk::Pixbuf, in the second column should be the stock icon. However, when I run the program, the first column remains empty. There are no compile or run-time errors or warnings.
My final application will display a matrix of about 100 rows and about 35 columns of mostly tiny icons allowing a quick overview of activities done on the different days of a month. None of these icons will be stock icons.
Extra Information: Following the program execution using a debugger, I found that the Gtk::ListStore's first column wants data of type gtkmm__GdkPixbuf. The type of pb in the line row[cols.m_pb] = pb is GdkPixbuf. The type GdkPixbuf cannot be converted to gtkmm__GdkPixbuf automatically, causing the value to be set to 0 (NULL). Obviously this does not solve the problem, but might help to solve the problem.
Thanks for the help and best wishes for 2015,
Wim
This is the file mwe.glade:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 -->
<interface>
<requires lib="gtk+" version="3.12"/>
<object class="GtkAccelGroup" id="accelgroup1"/>
<object class="GtkApplicationWindow" id="mainwindow">
<property name="can_focus">False</property>
<property name="show_menubar">False</property>
<child>
<object class="GtkGrid" id="mainbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkTreeView" id="treattree">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="vexpand">True</property>
<property name="hscroll_policy">natural</property>
<property name="model">treatstore</property>
<property name="rules_hint">True</property>
<property name="search_column">0</property>
<property name="fixed_height_mode">True</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="sel1"/>
</child>
<child>
<object class="GtkTreeViewColumn" id="col1">
<property name="sizing">fixed</property>
<property name="fixed_width">32</property>
<property name="title">1</property>
<child>
<object class="GtkCellRendererPixbuf" id="cell1">
<property name="width">16</property>
<property name="height">16</property>
</object>
<attributes>
<attribute name="pixbuf">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="col2">
<property name="sizing">fixed</property>
<property name="fixed_width">32</property>
<property name="title">2</property>
<child>
<object class="GtkCellRendererPixbuf" id="cell2"/>
<attributes>
<attribute name="stock-id">1</attribute>
</attributes>
</child>
</object>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
</object>
</child>
</object>
<object class="GtkListStore" id="treatstore">
<columns>
<!-- column-name col1 -->
<column type="GdkPixbuf"/>
<!-- column-name col2 -->
<column type="gchararray"/>
</columns>
</object>
</interface>
The file mwe.cpp:
#include <gtkmm.h>
namespace ws
{
class App : public Gtk::Application
{
protected:
App() : Gtk::Application("nl.mwe.mwe"), m_mainwindow(0)
{
Glib::set_application_name("MWE");
}
public:
static Glib::RefPtr<App> create(int &argc, char **&argv)
{
return Glib::RefPtr<App>(new App());
}
void init(Glib::RefPtr<Gtk::Builder> builder);
int run()
{
return Gtk::Application::run(*m_mainwindow);
}
private:
Gtk::ApplicationWindow *m_mainwindow;
};
// Definition of the column references
class ModelColumns : public Gtk::TreeModelColumnRecord
{
public:
ModelColumns()
{
add(m_pb);
add(m_stock);
}
Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf> > m_pb;
Gtk::TreeModelColumn<Glib::ustring> m_stock;
};
static ModelColumns col;
} // End namespace ws
/**
* \brief Initialize the app
* \param[in] builder The builder object
*
* Here is where the list store is populated with the Gdk::Pixbuf
*/
void ws::App::init(Glib::RefPtr<Gtk::Builder> builder)
{
builder->get_widget("mainwindow", m_mainwindow);
m_mainwindow->show();
Glib::RefPtr<Gtk::ListStore> store =
Glib::RefPtr<Gtk::ListStore>::cast_static(
builder->get_object("treatstore"));
Gtk::TreeModel::Row row = *store->append();
// The line below loads the stock icon as a pixbuf.
Glib::RefPtr<Gdk::Pixbuf> pb =
Gtk::IconTheme::get_default()->load_icon("gtk-apply", 16);
row[col.m_pb] = pb;
row[col.m_stock] = "gtk-apply";
}
int main (int argc, char *argv[])
{
Glib::RefPtr<ws::App> myapp = ws::App::create(argc, argv);
Glib::RefPtr<Gtk::Builder> builder = Gtk::Builder::create();
builder->add_from_file("mwe.glade");
myapp->init(builder);
return myapp->run();
}
After finding the problems in the types as shown in the Extra Information
section in the question, I decided to create the store by hand. The definition
of the GtkListStore was removed from the glade file. The ws::App::init()
method was changed to:
void ws::App::init(Glib::RefPtr<Gtk::Builder> builder)
{
builder->get_widget("mainwindow", m_mainwindow);
Gtk::TreeView *treeview = 0;
builder->get_widget("treattree", treeview);
Glib::RefPtr<Gtk::ListStore> store =
Gtk::ListStore::create(col);
treeview->set_model(store);
Gtk::TreeModel::Row row = *store->append();
// The line below loads the stock icon as a pixbuf.
Glib::RefPtr<Gdk::Pixbuf> pb =
Gtk::IconTheme::get_default()->load_icon("gtk-apply", 16);
row[col.m_pb] = pb;
row[col.m_stock] = "gtk-apply";
m_mainwindow->show();
}
Although this is not as flexible as hoped, it does fix the problem.
Related
I've been following a project based book which uses gtk and glade to build a UI. Went all fine until I got to using a gtk::Switch which the book uses like this:
let builder = gtk::Builder::from_string(include_str!("glade_config.glade"));
// ...
let is_dead_switch: gtk::Switch = builder
.get_object("is_dead_switch")
.unwrap();
Later on, to get the switch state it uses is_dead_switch.get_activate() but the method seems to no longer be a thing. I've looked into the documentation and found that gtk::Switch only has gtk::Switch::new listed as method. Anyone knows what's missing or what's wrong?
Cargo.toml dependencies:
[dependencies]
gio = "0.9.1"
[dependencies.gtk]
version = "0.9.2"
features = ["v3_22"]
glade config file stating this part:
<child>
<object class="GtkSwitch" id="is_dead_switch">
<property name="visible">True</property>
<property name="can_focus">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
PyQt 5
Python 3.5
I have a Windows service that cannot be started for a few seconds after it has been stopped. If you try it returns error 1053. When I try to start it during this "unresponsiveness period" with win32serviceutil. StartService() from a QThread (with a worker inside), StartService() runs for about 20 seconds and finally returns error 1053. The problem is that despite StartService() being run in a separate thread, it will also block the main GUI thread. Here's my sample code:
import sys
from PyQt5 import uic
from PyQt5.QtWidgets import QApplication, QMainWindow, QMessageBox
from PyQt5.QtCore import Qt, QObject, QThread, pyqtSignal, pyqtSlot
from win32serviceutil import StartService
class Worker(QObject):
finished = pyqtSignal()
done = pyqtSignal("PyQt_PyObject")
def __init__(self, func, *args):
super().__init__()
self.func = func
self.args = args
def run(self):
try:
result = self.func(*self.args)
except Exception as e:
result = e
self.done.emit(result) # Pass function return.
self.finished.emit()
Ui_MainWindow, QtBaseClass = uic.loadUiType("window.ui")
class TestApp(QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
# Hide What's This button and show only close button.
self.setWindowFlags(Qt.WindowTitleHint | Qt.WindowCloseButtonHint)
self.text_box.returnPressed.connect(self.run_thread)
self.worker = None
self.thread = None
self.go_button.clicked.connect(self.run_thread)
def run_thread(self):
if self.text_box.text().strip():
# Start service from generic worker inside a QThread.
self.worker = Worker(StartService, self.text_box.text().strip())
self.thread = QThread()
self.worker.moveToThread(self.thread)
self.thread.started.connect(self.worker.run)
self.worker.done.connect(self.done)
self.worker.finished.connect(self.thread.quit)
self.worker.finished.connect(self.worker.deleteLater)
self.thread.finished.connect(self.thread.deleteLater)
self.thread.start()
self.busy(True) # Activate progress busy mode.
def busy(self, status):
end = 0 if status else 100 # 0 is busy progress bar, 100 is inactive.
self.p_bar.setRange(0, end)
#pyqtSlot("PyQt_PyObject")
def done(self, result):
self.busy(False) # Deactivate progress bar.
if isinstance(result, Exception):
title = "Error"
msg = str(result)
icon = QMessageBox.Critical
else:
title = "Started"
msg = "Done"
icon = QMessageBox.Information
# Show message box with result.
dialog = QMessageBox(self)
dialog.setWindowTitle(title)
dialog.setText(msg)
dialog.setStandardButtons(QMessageBox.Ok)
dialog.setIcon(icon)
dialog.exec_()
def main():
program = QApplication(sys.argv)
svc_stopper = TestApp()
svc_stopper.show()
sys.exit(program.exec_())
if __name__ == "__main__":
main()
This is the window.ui file:
<?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>230</width>
<height>120</height>
</rect>
</property>
<property name="windowTitle">
<string>Start Service</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QPushButton" name="go_button">
<property name="geometry">
<rect>
<x>76</x>
<y>13</y>
<width>81</width>
<height>31</height>
</rect>
</property>
<property name="text">
<string>Start Service</string>
</property>
<property name="autoDefault">
<bool>true</bool>
</property>
</widget>
<widget class="QProgressBar" name="p_bar">
<property name="geometry">
<rect>
<x>10</x>
<y>90</y>
<width>211</width>
<height>23</height>
</rect>
</property>
<property name="value">
<number>0</number>
</property>
<property name="textVisible">
<bool>false</bool>
</property>
</widget>
<widget class="QLineEdit" name="text_box">
<property name="geometry">
<rect>
<x>10</x>
<y>60</y>
<width>211</width>
<height>20</height>
</rect>
</property>
<property name="placeholderText">
<string>Service display name</string>
</property>
<property name="clearButtonEnabled">
<bool>false</bool>
</property>
</widget>
</widget>
</widget>
<tabstops>
<tabstop>go_button</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>
After hours finally got why my app crashes after obfuscating by Obfuscar. That is StringHiding in MyClass. So settings for module now is
<SkipStringHiding type="Myspacename.MyClass" name="*" />
Now I need to hide only some of the strings inside MyClass. For example
private const string TrialLicenseKey = "AEAF3-N4C7K-BWDTV-3CLZB-XXXXX";
I was trying some combinatons of settings, but strings are still visible in Reflector.
Is ForceStringHiding supported? What is for name parameter? String content, var name, etc.?
<ForceStringHiding type="Myspacename.MyClass" name="???" />
Can't get why i see unobfuscated private static strings in Reflector
static Debugging()
{
A = new object();
__public = "AOMRDQELD+0rFgbQxySAHrBpU3N8RF1i3rXkgSC79aXEgE=";
D = "ActivationHardwareId";
d = "LicenseKey";
E = "ActivationKey";
...
}
settings for Obfuscar
<Var name="KeepPublicApi" value="true" />
<Var name="HidePrivateApi" value="true" />
<Var namr="HideStrings" value="true" />
When working with CSV files and restarting a FAILED Job, a StepExecutionListner and associated beforeStep( ....) method can be used to position
the reader within the file. So the code could look something like:
public void beforeStep(StepExecution stepExecution) {
ExecutionContext executionContext = stepExecution.getExecutionContext();
if (executionContext.containsKey(getKey(LINES_READ_COUNT))) {
long lineCount = executionContext.getLong(getKey(LINES_READ_COUNT));
LineReader reader = getReader();
Object record = "";
while (reader.getPosition() < lineCount && record != null) {
record = readLine();
}
}
} // Or something similar
My question is how do you achieve the same thing when working with a StaxEventItemReader?
My batch_step_execution_context looks something like {"string":"StaxEventItemReader.read.count","int":6}. So in my case the
the first 5 XML fragment were successfully processed and upon restarting the Job I would like to start processing from XML fragment number 6 onwards.
Given the config below, how would I position the reader within the XML file?
<batch:job id="reportJob" restartable="true">
<batch:step id="step1">
<batch:tasklet>
<batch:chunk reader="xmlItemReader" writer="cvsFileItemWriter" processor="filterReportProcessor"
commit-interval="1">
</batch:chunk>
<batch:listeners>
<batch:listener ref="step1Listener" />
</batch:listeners>
</batch:tasklet>
</batch:step>
</batch:job>
<bean id="step1Listener" class="com.mkyong.listeners.Step1Listener" />
<bean id="filterReportProcessor" class="com.mkyong.processor.FilterReportProcessor" />
<bean id="xmlItemReader" class="org.springframework.batch.item.xml.StaxEventItemReader">
<property name="fragmentRootElementName" value="record" />
<property name="resource" value="classpath:xml/report.xml" />
<property name="unmarshaller" ref="reportUnmarshaller" />
</bean>
<!-- Read and map values to object, via jaxb2 -->
<bean id="reportUnmarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.mkyong.model.Report</value>
</list>
</property>
</bean>
Environment - spring-batch-core-2.2.0; spring-core-3.2.2
Test Input File
Convert a XML file into a CSV file.
<company>
<record refId="1001">
<name>mkyong</name>
<age>31</age>
<dob>31/8/1982</dob>
<income>200,000</income>
</record>
<record refId="1002">
<name>kkwong</name>
<age>30</age>
<dob>26/7/1983</dob>
<income>100,999</income>
</record>
<record refId="1003">
<name>joel</name>
<age>29</age>
<dob>21/8/1984</dob>
<income>1,000,000</income>
</record>
<record refId="1004">
<name>leeyy</name>
<age>29</age>
<dob>21/3/1984</dob>
<income>80,000.89</income>
</record>
<record refId="1005">
<name>Grant</name>
<age>29</age>
<dob>21/3/1984</dob>
<income>80,000.89</income>
</record>
</company>
Test Run 1
After processing two records in the input file, I forced a RunTimeException.
batch_job_execution --->> "FAILED";"FAILED";"java.lang.RuntimeException: Get me out of here!
batch_step_execution_context --->> {"string":"StaxEventItemReader.read.count","int":2}
Output CSV file --->> 1001,mkyong,31,31/08/1982,200000
1002,kkwong,30,26/07/1983,100999
Test Run 2
Process all "remaining data", so expecting .... refId="1003", refId="1004", refId="1005"
batch_job_execution --->> "COMPLETED";"COMPLETED";"''";"2015-01-25 16:18:08.587"
batch_step_execution_context --->> {"string":"StaxEventItemReader.read.count","int":6}
Output CSV file --->> 1001,mkyong,31,31/08/1982,200000
1002,kkwong,30,26/07/1983,100999
1003,joel,29,21/08/1984,1000000
1004,leeyy,29,21/03/1984,80000.89
1005,Grant,29,21/03/1984,80000.89
Test Result
Unfortunately it looks like the StaxEventItemReader is reading from the beginning of the file, rather than re-positioning itself based on the value of StaxEventItemReader.read.count which is set to 2 after the first test.
You don't need to configure anything, this is already the default behavior of the StaxEventItemReader. When it opens it repositions itself from the read count in the step execution context.
I want to display MainWindow, in full screen and its contents should resize accordingly to the size of the monitor:
My MainWindow.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>820</width>
<height>651</height>
</rect>
</property>
<property name="windowTitle">
<string>metaio SDK – Qt Tutorials</string>
</property>
<widget class="QWidget" name="centralwidget">
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<layout class="QVBoxLayout" name="mainLayout">
<item alignment="Qt::AlignHCenter">
<widget class="QGraphicsView" name="graphicsView">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>1300</width>
<height>768</height>
</size>
</property>
<property name="resizeAnchor">
<enum>QGraphicsView::NoAnchor</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="buttonLayout">
<item>
<widget class="QPushButton" name="quitTutorialButton">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>« Back</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
<slots>
<slot>on_load_arel()</slot>
<slot>on_load_file()</slot>
<slot>on_close_tab(int)</slot>
<slot>on_save_and_preview()</slot>
<slot>on_preview_channel()</slot>
</slots>
</ui>
some code of my MainWindow.cpp:
...
setupUi(this);
quitTutorialButton->setVisible(false);
QObject::connect(quitTutorialButton, SIGNAL(clicked()), this, SLOT(onQuitTutorialButtonClicked()));
m_pMenu = new Menu(this, this);
// Init the main view for the scene using OpenGL
QGLWidget *glWidget = new QGLWidget(QGLFormat(QGL::SampleBuffers));
m_pGraphicsView = graphicsView;
m_pGraphicsView->setScene(m_pMenu);
m_pGraphicsView->setViewport(glWidget);
m_pGraphicsView->setFrameShape(QFrame::NoFrame);
some code in my Menu.cpp:
m_pWebView = new QGraphicsWebView();
addItem(m_pWebView);
m_pWebView->resize(1300, 768); // dont want this to be static
QObject::connect(m_pWebView, SIGNAL(linkClicked(const QUrl&)), this, SLOT(linkClicked(const QUrl&)));
QTimer::singleShot(20, this, SLOT(loadContent()));
Please help me out.
Edit:
If you see, i have added QGraphicsWebView programatically. I am running this solution on my notebook, with 1366 x 768 resolution. If i want to use entire screen space, i have to give size to my QGraphicsWebView (line with comment added at the end) and to my QGraphicsView that lies in my MainWindow.ui. I want to remove this static part, and make it dynamic.
If you're using QLayout managers then all you should need to do is set the window state to full screen: QWidget::setWindowState. The layout managers should take care of the rest, most likely you'll need to set the spacing and use some QSpacers to get the elements exactly where you want them.
About the fullscreen issue: have you tried with QMainWindow::showFullScreen() ?
Reply to the edit:
I don't see any reason for those nested layouts, it is kinda messed up. Instead of having
-- mainLayout
|-- graphicsView
|-- buttonLayout <- why layout only one element??
|-- quitTutorialButton
try with this simpler layout
-- mainLayout
|-- graphicsView
|-- quitTutorialButton
Then, change the fixed size policy to MinimumExpanding instead.
Last advice: since looks like you layout your items by hand, never insert the outermost layout by hand. If you do so, the elements in it will never scale to the QMainWindow size.
Instead, right-click in an empty portion of the central widget, select Layout and then choose the type of layout you want to apply. This of course is needed only for the outmost layout: for the remaining, inner ones, you can add them by simple drag&drop as usual.