I have .glade
file written in glade ver. 3.38 and PyGObject 3.38. Right now I'm on Ubuntu 21.10 with PyGObject 3.40. So, I converting my glade from gtk3 to gtk4 with gtk4-builder-tool
but i got an error gi.repository.GLib.Error: gtk-builder-error-quark: No function named btnProcess_clicked_cb. (14)
Glade file
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk" version="4.0"/>
<object class="GtkWindow" id="graywindow">
<signal name="destroy" handler="graywindow_destroy_cb" swapped="no"/>
<property name="child">
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">1811
Jq
IC</property>
<property name="width-chars">0</property>
<attributes>
<attribute name="font-desc" value="Sans Bold 14"></attribute>
<attribute name="style" value="normal"></attribute>
</attributes>
</object>
</child>
<child>
<object class="GtkBox">
<property name="homogeneous">1</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Image Ori</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="homogeneous">1</property>
<child>
<object class="GtkImage" id="imgOri">
<property name="icon-name">image</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="homogeneous">1</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Prewitt</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Global Threshold
</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Otsu</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="homogeneous">1</property>
<child>
<object class="GtkImage" id="imgGray">
<property name="icon-name">image</property>
</object>
</child>
<child>
<object class="GtkImage" id="imgGT">
<property name="icon-name">image</property>
</object>
</child>
<child>
<object class="GtkImage" id="imgO">
<property name="icon-name">image</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="homogeneous">1</property>
<child>
<object class="GtkButton" id="btnProcess">
<property name="label" translatable="yes">Process</property>
<property name="focusable">1</property>
<property name="receives-default">1</property>
<signal name="clicked" handler="btnProcess_clicked_cb" swapped="no"/>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="homogeneous">1</property>
<child>
<object class="GtkEntry">
<property name="focusable">1</property>
</object>
</child>
<child>
<object class="GtkButton" id="btnBrowse">
<property name="label" translatable="yes">browse</property>
<property name="focusable">1</property>
<property name="receives-default">1</property>
<signal name="clicked" handler="btnBrowse_clicked_cb" swapped="no"/>
</object>
</child>
</object>
</child>
</object>
</property>
</object>
</interface>
Python file
from gi.repository import Gtk
import numpy as np
import cv2
import gi
from matplotlib import pyplot as plt
import sys
gi.require_version('Gtk', '4.0')
class grayProcess:
def graywindow_destroy_cb(self, object, data=None):
Gtk.main_quit()
def btnBrowse_clicked_cb(self, object, data=None):
self.dialog = Gtk.FileChooserDialog(
'Please Choose a File',
None,
Gtk.FileChooserAction.OPEN,
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
self.response = self.dialog.run()
global url
if self.response == Gtk.ResponseType.OK:
self.search = self.builder.get_object('txtSearch')
imgOri = self.builder.get_object('imgOri')
url = self.dialog.get_filename()
self.search.set_text(str(url))
imgOri.set_from_file(url)
elif self.response == Gtk.ResponseType.cancel:
print('Cancel Clicked')
self.dialog.destroy()
def btnProcess_clicked_cb(self, object, data=None):
self.img = cv2.imread(url)
imgGrey = self.builder.get_object('imgGray')
# Prewitt Start
self.gray = cv2.cvtColor(self.img, cv2.COLOR_BGR2GRAY)
img_gaussian = cv2.GaussianBlur(self.gray, (3, 3), 0)
kernelx = np.array([[1, 1, 1], [0, 0, 0], [-1, -1, -1]])
kernely = np.array([[-1, 0, 1], [-1, 0, 1], [-1, 0, 1]])
img_prewittx = cv2.filter2D(img_gaussian, -1, kernelx)
img_prewitty = cv2.filter2D(img_gaussian, -1, kernely)
cv2.imwrite('image/prewitt.jpg', img_prewittx + img_prewitty)
imgGrey.set_from_file('image/prewitt.jpg')
# Prewitt End
# Global Threshold Start
self.img = cv2.imread(url, 0)
imgGt = self.builder.get_object('imgGT')
dimensao = self.img.shape
img = cv2.medianBlur(self.img, 5)
ret, th1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
value = cv2.countNonZero(th1)
titles = ['Original Image', 'Global Thresholding (v = 127)']
images = [img, th1]
for i in range(len(images)):
plt.subplot(2, 2, i+1), plt.imshow(images[i], 'gray')
plt.title(titles[i])
plt.xticks([]), plt.yticks([])
cv2.imwrite('image/Global Threshold.jpg', th1)
imgGt.set_from_file('image/Global Threshold.jpg')
# Global Threshold End
# Start Otsu
self.img = cv2.imread(url, 0)
imgo = self.builder.get_object('imgO')
ret, thresh2 = cv2.threshold(self.img, 127, 255, cv2.THRESH_BINARY_INV)
titles = ['Original Image', 'BINARY',
'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']
images = [self.img, thresh2]
for i in range(0, 6):
plt.subplot(2, 3, i+1), plt.imshow(images[i], 'gray')
plt.title(titles[i])
plt.xticks([]), plt.yticks([])
cv2.imwrite('image/otsu.jpg', thresh2)
imgo.set_from_file('image/otsu.jpg')
# Otsu End
def __init__(self):
self.gladefile = ('uts_cv.glade')
self.builder = Gtk.Builder()
self.builder.add_from_file(self.gladefile)
self.builder.connect_signals(self)
self.window = self.builder.get_object('graywindow')
self.window.show()
if __name__ == '__main__':
main = grayProcess()
Gtk.main()
According to gtk4 docs, https://docs.gtk.org/gtk4/migrating-3to4.html#adapt-to-gtkbuilder-api-changes
gtk_builder_connect_signals()
no longer exists. Instead, signals are always connected automatically. If you need to add user data to your signals,gtk_builder_set_current_object()
must be called. An important caveat is that you have to do this before loading any XML. This means if you need to usegtk_builder_set_current_object()
, you can no longer usegtk_builder_new_from_file()
,gtk_builder_new_from_resource()
, orgtk_builder_new_from_string()
. Instead, you must use vanillagtk_builder_new()
, then callgtk_builder_set_current_object()
, then load the XML usinggtk_builder_add_from_file()
,gtk_builder_add_from_resource()
, orgtk_builder_add_from_string()
. You must check the return value for failure and manually abort withg_error()
if something went wrong.
The easy way to use signals now, imo is Gtk.Template
, you can look at the documentation here, https://pygobject.readthedocs.io/en/latest/guide/gtk_template.html