how to use the set_cell_data_func function in vala to change the layout of my cell depending on its content? - gtk

I'm trying to use the set_cell_data_func on a Gtk.TreeViewColumn. My code compiles but gives a segmentation error when running. I have also tried the insert_column_with_data_func instead but the result is the same.
Here is my code, i hope you'll be able to help me :)
public class Application : Gtk.Window {
public Application () {
this.destroy.connect (Gtk.main_quit);
this.set_default_size (600, 400);
Gtk.ListStore store = new Gtk.ListStore (2, typeof(int),
typeof(string));
Gtk.TreeIter iter;
store.append (out iter);
store.set (iter, 0, 0, 1, "A");
store.append (out iter);
store.set (iter, 0, 1, 1, "B");
store.append (out iter);
store.set (iter, 0, 0, 1, "C");
store.append (out iter);
store.set (iter, 0, 0, 1, "D");
Gtk.TreeView view = new Gtk.TreeView.with_model (store);
this.add(view);
Gtk.CellRendererText cell = new Gtk.CellRendererText ();
Gtk.TreeViewColumn col = new Gtk.TreeViewColumn.with_attributes (
"Value", cell, "text", 1);
col.set_cell_data_func (cell, (Gtk.CellLayoutDataFunc)render_value);
view.append_column (col);
}
public void render_value (Gtk.TreeViewColumn column, Gtk.CellRendererText
cell, Gtk.TreeModel model, Gtk.TreeIter iter) {
var val = Value (typeof(int));
model.get_value (iter, 0, out val);
if ((int)val==1) (cell as Gtk.CellRendererText).background = "#b8cb04";
val.unset ();
}
public static int main (string[] args) {
Gtk.init (ref args);
Application app = new Application ();
app.show_all ();
Gtk.main ();
return 0;
}
}

After debugging the translated c sources i found the bug.
vala translates
public void render_value (Gtk.TreeViewColumn column,
Gtk.CellRendererText cell,
Gtk.TreeModel model,
Gtk.TreeIter iter)
from your code to the following c equivalent
void application_render_value (Application* self,
GtkTreeViewColumn* column,
GtkCellRendererText* cell,
GtkTreeModel* model,
GtkTreeIter* iter)
I compared this with the reference docs.
There the signature of the data function is defined as follows
void (*GtkCellLayoutDataFunc) (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
GtkTreeModel *tree_model,
GtkTreeIter *iter,
gpointer data);
With regard to the method you have implemented that means that the arguments are shifted by one to the right. So the following applies to your data func/method
column is in fact the cell renderer
cell is the tree model
model is the iterator and
iter is the data that is passed to the function/method
If you change the declaration of your data func/method to
public void render_value (Gtk.CellRendererText cell,
Gtk.TreeModel model, Gtk.TreeIter iter, Object data)
everything should work fine.
Maybe the reason of this is that CellLayoutDataFunc is defined as public delegate void. But since i don't know anything about vala it's just a guess. If it's not the case you may post this on a related vala mailing list.

Related

Why GtkWidget is not being found

I have following simple application which creates a window with Label, Entry and Button:
using Gtk;
public static int main(string[] args) {
Gtk.init(ref args);
var mywin = new MyWindow("Entrypad");
mywin.show_all();
Gtk.main();
return 0;
}
public class MyWindow : Window{
public MyWindow(string stitle) {
this.title = stitle;
this.destroy.connect(Gtk.main_quit);
var grid = new Grid();
this.add(grid);
var lab = new Label("Mylabel:");
lab.set_xalign(1);
grid.attach(lab, 0, 0, 1, 1 );
Entry ent = new Entry();
grid.attach(ent, 1, 0, 1, 1 );
var printButton = new Button.with_label("Print Button");
grid.attach(printButton, 0, 1, 1, 1);
printButton.clicked.connect( printButtonFn );
}
}
private void printButtonFn(){
print("In print fn; \n");
}
Above code compiles and works all right. However, I want to show a dialog box, hence I modify printButtonFn and add code taken from here:
private void printButtonFn(){
print("In print fn; \n");
quick_message(this, "Message for dialog box.");
}
// Function to open a dialog box with a message
void quick_message (GtkWindow *parent, gchar *message) {
GtkWidget *dialog, *label, *content_area;
GtkDialogFlags flags;
flags = GTK_DIALOG_DESTROY_WITH_PARENT;
dialog = gtk_dialog_new_with_buttons ("Message",
parent,
flags,
_("_OK"),
GTK_RESPONSE_NONE,
NULL);
content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
label = gtk_label_new (message);
g_signal_connect_swapped (dialog,
"response",
G_CALLBACK (gtk_widget_destroy),
dialog);
gtk_container_add (GTK_CONTAINER (content_area), label);
gtk_widget_show_all (dialog);
}
However, above is giving error:
$ valac --pkg gtk+-3.0 mysrc.vala
rnskeletalGUI_dialog_soques.vala:50.21-50.21: error: syntax error, expected identifier
GtkWidget *dialog, *label, *content_area;
^
Compilation failed: 1 error(s), 0 warning(s)
Where is the problem and how can it be solved?
Two problems.
First, it's Gtk.Widget not GtkWidget. Or, if you have a using Gtk; in that code too, you can just use Widget.
Second, and the one valac is erroring about, is that unlike C, in Vala the pointer goes with the type, not the variable. So if you want three pointers to Gtk.Widget you should write GtkWidget* dialog, label, content_area; not Gtk.Widget *dialog, *label, *content_area;
That said, you shouldn't be using pointers here. Pointers in Vala basically opt you out of the memory management system, and you should almost never use them... think of it a bit like the "unsafe" keyword in some languages.

How to pass widget and data from one file to another file in different class?

Beginner-level questions. I’m creating a counter application (first application from The 7 Tasks). I created this application in one file and it is working fine. Following is the code.
class Application : Gtk.Application {
public int val = 0;
public Application() {
Object(
application_id: "com.github.uname.counter",
flags: ApplicationFlags.FLAGS_NONE
);
}
protected override void activate() {
var window = new Gtk.ApplicationWindow(this);
window.default_height = 30;
window.default_width = 300;
window.title = "Counter";
var grid = new Gtk.Grid();
grid.column_homogeneous = true;
grid.row_homogeneous = true;
grid.row_spacing = 5;
grid.column_spacing = 5;
var entry = new Gtk.Entry();
entry.text = val.to_string();
entry.editable = false;
grid.attach(entry, 0, 0, 1, 1);
var button1 = new Gtk.Button.with_label("Counter");
grid.attach(button1, 1, 0, 1, 1);
button1.clicked.connect (() => {
this.val = this.val + 1;
entry.text = this.val.to_string();
});
window.add(grid);
window.show_all();
}
public static int main(string[] args) {
var application = new Application();
return application.run(args);
}
}
Now, I'm trying to divide the above code into separate files such as Application.vala, Entry.vala, and Button.vala. Here is the code for these files.
Code for Application.vala.
class Application : Gtk.Application {
public int val = 0;
public Application() {
Object(
application_id: "com.github.chauhankiran.counter",
flags: ApplicationFlags.FLAGS_NONE
);
}
protected override void activate() {
var window = new Gtk.ApplicationWindow(this);
window.default_height = 30;
window.default_width = 300;
window.title = "Counter";
var grid = new Gtk.Grid();
grid.column_homogeneous = true;
grid.row_homogeneous = true;
grid.row_spacing = 5;
grid.column_spacing = 5;
var entry = new Entry(val);
grid.attach(entry, 0, 0, 1, 1);
var button1 = new Button(val);
grid.attach(button1, 1, 0, 1, 1);
window.add(grid);
window.show_all();
}
public static int main(string[] args) {
var application = new Application();
return application.run(args);
}
}
Code for Entry.vala.
public class Entry : Gtk.Entry {
public Entry(int val) {
text = val.to_string();
}
construct {
editable = false;
}
}
Code for Button.vala.
public class Button : Gtk.Button {
// Is it correct?
public int val;
public Button(int val) {
this.val = val;
}
construct {
label = "Counter";
}
// How to write this within Button.vala from Application.vala?
// How to get entry widget in this class?
button1.clicked.connect (() => {
this.val = this.val + 1;
entry.text = this.val.to_string();
});
}
Now, I have the following questions.
Entry.vala accepts val as initial value. I don't know how to pass it in construct. So, I used public object method. Is it correct way?
In Button.vala I need val as well access to entry so that I can get access to entry in Button.vala? Or this is incorrect way to do the code? If that is that is the case, please suggest correct way. Currently separate files code throws error as I don’t know how to connect and pass the information correctly.
The 7 Tasks are a good exercise to learn, and you seem to be off to a great start!
Entry.vala accepts val as initial value. I don't know how to pass it in construct. So, I used public object method. Is it correct way?
The preferred way to handle construction in Vala is using GObject-style construction: https://wiki.gnome.org/Projects/Vala/Tutorial#GObject-Style_Construction
What you're doing would technically work, but using the GObject-style you'd end up with something like the following:
public class Entry : Gtk.Entry {
public Entry(int val) {
Object (
text: val.to_string(),
editable: false
);
}
}
The important things to note here are:
This only works for properties declared as construct or set
The syntax is slightly different than what you were doing (property: value vs. member = value)
And one other little optimization:
editable is also a property that can be set in the constructor, so no need for a construct block here!
Notice that you can make some similar changes to your Button class as well!
In Button.vala I need val as well access to entry so that I can get
access to entry in Button.vala? Or this is incorrect way to do the
code? If that is that is the case, please suggest correct way.
Currently separate files code throws error as I don’t know how to
connect and pass the information correctly.
Currently your Button code has references to the Entry in it. I would advise against this from an object-oriented programming (OOP) perspective (you may hear people toss around terms like Single-Responsibility or Separation of Concerns, etc.), but the gist is that the button should just focus on being what it is: a button. A button doesn't need to be aware of the presence of the entry, and the entry doesn't need to exist in order to have a button. Your logic of handling what happens between widgets when the button is clicked should happen at a level above. In this case, that would be in your Application class where you've created both of those widgets:
...
var entry = new Entry(val);
grid.attach(entry, 0, 0, 1, 1);
var button1 = new Button(val);
grid.attach(button1, 1, 0, 1, 1);
button1.clicked.connect (() => {
// Update the entry
});
...
Let's take a quick look at your button:
public class Button : Gtk.Button {
// Is it correct?
public int val;
...
It's not wrong, and there are many ways to do what you're doing. So let's roll with it as is.
At this point you've got your button which updates an internal int value every time it's clicked and you now need to update the entry to display the new value. Currently you have:
button1.clicked.connect (() => {
this.val = this.val + 1;
entry.text = this.val.to_string();
});
Since this is now being handled in the Application class, you'll need to change those references to this, since you want to reference and update val from the button, not the variable in Application that you're using for the initial value:
button1.clicked.connect (() => {
button1.val = button1.val + 1;
entry.text = button1.val.to_string();
});
Hopefully that helped a bit, you were 99% of the way there with splitting it into multiple classes! Keep it up, and good luck on the next tasks!

i have written a code which shows image slideshow now i want to put a button on it how can i do that?

I have tried this code by setting setComponentZOrder() but it also did not worked please give me some suggestion how can i achieve this goal to make an image slideshow and put a button on it in jframe
import java.awt.Image;
import java.awt.*;
import java.awt.event.ActionListener;
import javafx.event.ActionEvent;
import javax.swing.JFrame;
import javax.swing.*;
public class slidemain extends JFrame {
JLabel jl;
JButton b;
Timer tm;
int x = 0;
int w;
int h;
String[] list = {
"C:\\Users\\HARITI\\Desktop\\sat.jpg",
"C:\\Users\\HARITI\\Desktop\\mtab.jpg",
"C:\\Users\\HARITI\\Desktop\\abc.jpg"
};
public slidemain()
{
super("java slide show");
// w = super.getWidth();
// h = super.getHeight();
jl = new JLabel();
b = new JButton();
//b.setVisible(true);
super.setComponentZOrder(jl, 0);
super.setComponentZOrder(b, 1);
jl.setBounds(0, 100, 1350, 650);
setImageSize(2);
tm = new Timer(1500, new ActionListener(){
#Override
public void actionPerformed(java.awt.event.ActionEvent e) {
setImageSize(x);
x += 1;
if (x >= list.length)
{
x = 0;
}
}
});
add(jl);
tm.start();
setLayout(null);
getContentPane().setBackground(Color.decode("#bdb67b"));
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public void setImageSize(int i) {
ImageIcon icon = new ImageIcon(list[i]);
Image img = icon.getImage();
Image newimg = img.getScaledInstance(jl.getWidth(), jl.getHeight(), Image.SCALE_SMOOTH);
ImageIcon newimc = new ImageIcon(newimg);
jl.setIcon(newimc);
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
new slidemain();
}
}
This...
super.setComponentZOrder(jl, 0);
super.setComponentZOrder(b, 1);
is going to have no affect if neither of the components have been added to the container yet.
Which brings us to your next problem, you never actually add the button to anything
And event if you did, it wouldn't be displayed, because you're using a null layout
Avoid using null layouts, pixel perfect layouts are an illusion within modern ui design. There are too many factors which affect the individual size of components, none of which you can control. Swing was designed to work with layout managers at the core, discarding these will lead to no end of issues and problems that you will spend more and more time trying to rectify.
Maybe have a look at Why is it frowned upon to use a null layout in SWING? for some more details

iTextSharp 7 object reference not set to an instance of an object

Is there some recommendation to build tables with cells having paragraphs in order to avoid an exception at adding of some cell to table or table to document? I get this and I can't figure out what happens:
[NullReferenceException: Object reference not set to an instance of an object.]
iText.Layout.Renderer.TableRenderer.DrawBorders(DrawContext drawContext) +2493
iText.Layout.Renderer.TableRenderer.DrawChildren(DrawContext drawContext) +1497
iText.Layout.Renderer.AbstractRenderer.Draw(DrawContext drawContext) +153
iText.Layout.Renderer.TableRenderer.Draw(DrawContext drawContext) +637
iText.Layout.Renderer.AbstractRenderer.DrawChildren(DrawContext drawContext) +104
iText.Layout.Renderer.BlockRenderer.Draw(DrawContext drawContext) +525
iText.Layout.Renderer.TableRenderer.DrawChildren(DrawContext drawContext) +1382
iText.Layout.Renderer.AbstractRenderer.Draw(DrawContext drawContext) +153
iText.Layout.Renderer.TableRenderer.Draw(DrawContext drawContext) +637
iText.Layout.Renderer.DocumentRenderer.FlushSingleRenderer(IRenderer resultRenderer) +473
iText.Layout.Renderer.RootRenderer.AddChild(IRenderer renderer) +1999
iText.Layout.RootElement`1.Add(BlockElement`1 element) +92
iText.Layout.Document.Add(BlockElement`1 element) +81
Here is a simple snapshot (compared to the real project) using a Windows console project:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using iText.Layout;
using iText.Layout.Borders;
using iText.Layout.Element;
namespace iTextTest
{
public static class iTextSharpHelper
{
public static T SetBorderEx<T>(this ElementPropertyContainer<T> element, Border border)
where T : ElementPropertyContainer<T>
{
element.SetBorder(border);
return (T)element;
}
public static Paragraph Style(this BlockElement<Paragraph> element)
{
element
.SetBorderEx(iText.Layout.Borders.Border.NO_BORDER)
.SetFont(iText.Kernel.Font.PdfFontFactory.CreateFont(iText.IO.Font.FontConstants.HELVETICA))
.SetFontSize(10.0f)
.SetFixedLeading(12.0f)
.SetVerticalAlignment(iText.Layout.Properties.VerticalAlignment.BOTTOM)
.SetMargin(0f);
return (Paragraph)element;
}
}
class Program
{
private static float[] tableColumns = { 0.35f, 0.25f, 0.15f, 0.25f };
static void Main(string[] args)
{
iText.Kernel.Pdf.PdfDocument pdf = new iText.Kernel.Pdf.PdfDocument(new iText.Kernel.Pdf.PdfWriter("test.pdf"));
iText.Layout.Document document = new iText.Layout.Document(pdf, iText.Kernel.Geom.PageSize.A4);
document.SetMargins(50f, 50f, 25f, 50f);
iText.Layout.Element.Table mainTable = new iText.Layout.Element.Table(tableColumns)
.SetBorderEx(iText.Layout.Borders.Border.NO_BORDER)
.SetWidthPercent(100)
.SetHorizontalAlignment(iText.Layout.Properties.HorizontalAlignment.LEFT)
.SetPadding(0f);
for (int i = 0; i < 10; i++)
{
AddRow(mainTable, "ABCDEFGHIJ", "ABCDEFGHIJ", "ABCDEFGHIJ");
}
document.Add(mainTable);
document.Close();
}
private static void AddRow(iText.Layout.Element.Table table, string col1, string col2, string col3)
{
// Label
AddCell(table, col1, true)
.SetBorderTop(new iText.Layout.Borders.SolidBorder(iText.Kernel.Colors.Color.BLACK, 0.5f));
// Product - Voucher and price/pcs
AddCell(table, col2, true)
.SetBorderTop(new iText.Layout.Borders.SolidBorder(iText.Kernel.Colors.Color.BLACK, 0.5f));
// Message
AddCell(table, col3, true, 2)
.SetBorderTop(new iText.Layout.Borders.SolidBorder(iText.Kernel.Colors.Color.BLACK, 0.5f))
//.SetBorderRight(new iText.Layout.Borders.SolidBorder(iText.Kernel.Colors.Color.BLACK, 0.5f))
.SetHorizontalAlignment(iText.Layout.Properties.HorizontalAlignment.RIGHT)
.SetTextAlignment(iText.Layout.Properties.TextAlignment.RIGHT);
}
private static iText.Layout.Element.Cell AddCell(iText.Layout.Element.Table table, string text, bool setBold = false, int colSpan = 1)
{
iText.Layout.Element.Cell cell = new iText.Layout.Element.Cell(1, colSpan)
.SetBorderEx(iText.Layout.Borders.Border.NO_BORDER)
.SetVerticalAlignment(iText.Layout.Properties.VerticalAlignment.BOTTOM);
if (!string.IsNullOrEmpty(text))
{
iText.Layout.Element.Paragraph paragraph = new iText.Layout.Element.Paragraph(text)
.Style();
if (setBold)
paragraph.SetBold();
cell.Add(paragraph);
}
table.AddCell(cell);
return cell;
}
}
}
Note, a commented out line of code:
//.SetBorderRight(new iText.Layout.Borders.SolidBorder(iText.Kernel.Colors.Color.BLACK, 0.5f))
Adding it serves as a workaround to make the document render without the exception.
Given the sample code added by the OP the issue can easily be reproduced.
Furthermore after porting the code to iText/Java the issue could be reproduced there, too, cf. MikesTableIssue.java test method testMikesCode. Thus, it is no porting error from Java (the original iText code) to C#.
The sample could even be considerably simplified and still reproduce the issue:
try ( FileOutputStream target = new FileOutputStream("mikesTableIssueSimple.pdf");
PdfWriter pdfWriter = new PdfWriter(target);
PdfDocument pdfDocument = new PdfDocument(pdfWriter) )
{
Document document = new Document(pdfDocument);
Table mainTable = new Table(1);
Cell cell = new Cell()
.setBorder(Border.NO_BORDER)
//.setBorderRight(new SolidBorder(Color.BLACK, 0.5f))
.setBorderTop(new SolidBorder(Color.BLACK, 0.5f));
cell.add("TESCHTINK");
mainTable.addCell(cell);
document.add(mainTable);
}
(MikesTableIssue.java test method testSimplified)
The issue does not occur if one
removes setBorder(Border.NO_BORDER) or
removes setBorderTop(new SolidBorder(Color.BLACK, 0.5f)) or
adds setBorderRight(new SolidBorder(Color.BLACK, 0.5f)).
In this situation com.itextpdf.layout.renderer.TableRenderer.drawBorders(DrawContext) executes this code:
if (lastBorder != null) {
if (verticalBorders.get(j).size() > 0) {
if (i == 0) {
x2 += verticalBorders.get(j).get(i).getWidth() / 2;
} else if(i == horizontalBorders.size() - 1 && verticalBorders.get(j).size() >= i - 1 && verticalBorders.get(j).get(i - 1) != null) {
x2 += verticalBorders.get(j).get(i - 1).getWidth() / 2;
}
}
lastBorder.drawCellBorder(drawContext.getCanvas(), x1, y1, x2, y1);
}
while lastBorder is the SolidBorder instance, verticalBorders is [[null], [null]], j == 1 and i == 0.
Thus, some additional null checks ought to be introduced here.

How to display GtkTreeView with dummy data in Vala

I'm trying to display a GtkTreeView in a GtkApplication Window with some dummy data using Vala.
The problem is that the window appears to be empty, but after a closer look using GtkInspector I can see that the GtkTreeView is there but looks to be empty even thought the model is properly set and it has the appropriate data.
The code I have so far is:
main_window.vala:
using GLib;
using Gtk;
namespace MediaOrganizer
{
public class MainWindow: Gtk.ApplicationWindow
{
/* public constructor(s)/destructor*/
public MainWindow(string title)
{
Object(
border_width : 0,
window_position : WindowPosition.CENTER
);
header_ = new Gtk.HeaderBar();
fileModel_ = new FilesystemModel();
fileView_ = new Gtk.TreeView();
mainLayout_ = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
this.set_default_size(800, 480);
header_.set_title(title);
header_.set_show_close_button(true);
this.set_titlebar(header_);
fileView_.set_model(fileModel_);
this.size_allocate.connect(on_size_changed);
mainLayout_.add(fileView_);
add(mainLayout_);
}
void on_size_changed(Gtk.Allocation size)
{
}
/* private variables */
private Box mainLayout_;
private Gtk.HeaderBar header_;
private FilesystemModel fileModel_;
private Gtk.TreeView fileView_;
}
}
filesystem_model.vala:
using GLib;
using Gtk;
namespace MediaOrganizer
{
public class FilesystemModel: Gtk.TreeStore
{
public FilesystemModel()
{
GLib.Type columnTypes[2] = {
typeof(int),
typeof(string)
};
set_column_types(columnTypes);
Gtk.TreeIter it;
append(out it, null);
set_value(it, 0, 0);
set_value(it, 1, "aaaa");
append(out it, null);
set_value(it, 0, 1);
set_value(it, 1, "bbbb");
append(out it, null);
set_value(it, 0, 2);
set_value(it, 1, "cccc");
}
}
}
Add a TreeViewColumn for each column of your store : http://valadoc.org/#!api=gtk+-3.0/Gtk.TreeView