GTK# TreeViewColumn with multiple renderers - c#

I am working at chat with stickers on Mono C# with GTK# GUI. While googling i have founded that best widget for this purpose is TextView. Problem in creating ListStore for column with multiple renderers:
TreeView messageLog=new TreeView();
#Creating a column
TreeViewColumn messageColumn = new TreeViewColumn();
messageLog.AppendColumn(messageColumn);
#Creating model for tree
ListStore messageStore = new ListStore(typeof(string), typeof(Gdk.Pixbuf));
messageLog.Model = messageStore;
#Packing 2 renderers into column
CellRendererText textCell = new CellRendererText();
messageColumn.PackEnd(textCell, true);
messageColumn.AddAttribute(textCell, "text", 0);
CellRendererPixbuf stickerCell = new CellRendererPixbuf();
messageColumn.PackStart(stickerCell, false);
messageColumn.AddAttribute(stickerCell, "pixbuf", 1);
Add text to TreeView:
messageStore.AppendValues(value);
This way, i can add pictures to TreeView only with:
messageStore.AppendValues(null, new Gdk.Pixbug("red.png");
But it shows like in new column. Is there a better way to define ListStore or append values so picture will be shown in same column as message? Or maybe there is a better widget for this purpose?

You were right, I've been able to do it (more than one item in a single column), following (or inferring from) the Mono's Gtk# tree view tutorial.
namespace TreeViewMultipleRenderers
{
public class MainWindowView: Gtk.Window
{
public MainWindowView()
: base( Gtk.WindowType.Toplevel )
{
this.SetGeometryHints( this,
new Gdk.Geometry { MinHeight = 400, MinWidth = 600 },
Gdk.WindowHints.MinSize );
this.Build();
}
void BuildIcons()
{
this.IconYes = new Gdk.Pixbuf(
System.Reflection.Assembly.GetEntryAssembly(),
"TreeViewMultipleRenderers.Res.yes.png", 16, 16 );
this.IconNo = new Gdk.Pixbuf(
System.Reflection.Assembly.GetEntryAssembly(),
"TreeViewMultipleRenderers.Res.no.png", 16, 16 );
}
Gtk.TreeView BuildTreeView()
{
var toret = new Gtk.TreeView();
// Index column
var columnIndex = new Gtk.TreeViewColumn {
Title = "#"
};
var indexRenderer = new Gtk.CellRendererText();
columnIndex.PackStart( indexRenderer, expand: true );
columnIndex.AddAttribute( indexRenderer, "text", 0 );
// Data column
var columnData = new Gtk.TreeViewColumn {
Title = "Mixed column"
};
var dataRenderer1 = new Gtk.CellRendererPixbuf();
columnData.PackStart( dataRenderer1, expand: false );
columnData.AddAttribute( dataRenderer1, "pixbuf", 1 );
var dataRenderer2 = new Gtk.CellRendererText();
columnData.PackStart( dataRenderer2, expand: true );
columnData.AddAttribute( dataRenderer2, "text", 2 );
toret.AppendColumn( columnIndex );
toret.AppendColumn( columnData );
// Model
var store = new Gtk.ListStore( typeof( string ), typeof( Gdk.Pixbuf ), typeof( string ) );
toret.Model = store;
store.AppendValues( "1", this.IconYes, "works" );
store.AppendValues( "2", this.IconNo, "does not work" );
return toret;
}
void Build()
{
this.BuildIcons();
this.TreeView = this.BuildTreeView();
this.Add( this.TreeView );
}
public Gtk.TreeView TreeView {
get; set;
}
public Gdk.Pixbuf IconYes {
get; private set;
}
public Gdk.Pixbuf IconNo {
get; private set;
}
}
}
I can't see any important difference with the relevant parts of the code you posted, so I guess the problem must be elsewhere. You can find this code in the GtkTreeViewMultipleRenderers Github repository. I've also uploaded an executable in the releases section of the repository.
Hope this helps.

Related

ToolBar Icons showing when in secondary order Maui

So I'm coding in my toolbar items to sort through my data, but on iOS the images show up but on android it does the 3 dots like it's supposed to. I don't know if this is a bug with MAUI (I didn't see anything in the git about it). I know the secondary order is supposed to have the dots by default, but I'm pretty sure they shouldn't get overridden by pictures.
Here's my code for the toolbars:
public void SortByLocation()
{
view_model_.SortMethod = Utilities.PlanSortMethod.Distance;
sort_method_ = view_model_.SortMethod;
sort_method_string_ = ToolbarItems[0].Text = sort_by_location_string;
}
public void SortByName()
{
view_model_.SortMethod = Utilities.PlanSortMethod.Name;
sort_method_ = view_model_.SortMethod;
sort_method_string_ = ToolbarItems[0].Text = sort_by_name_string;
}
public void SortByNewest()
{
view_model_.SortMethod = Utilities.PlanSortMethod.DateLatest;
sort_method_ = view_model_.SortMethod;
sort_method_string_ = ToolbarItems[0].Text = sort_by_recent_string;
}
public void SortByOldest()
{
view_model_.SortMethod = Utilities.PlanSortMethod.DateEarliest;
sort_method_ = view_model_.SortMethod;
sort_method_string_ = ToolbarItems[0].Text = sort_by_earliest_string;
}
private void SortByLabelTapped()
{
// Do nothing for now. Ideally we would pop up the toolbar, but am unsure how to do it
}
private IList<ToolbarItem> GetSortToolbarItems()
{
var list = new List<ToolbarItem>();
// Add default item
list.Add(
new ToolbarItem(
sort_method_string_,
"mow.png",
SortByLabelTapped,
ToolbarItemOrder.Primary, 0)
);
// Add options to choose from
list.Add(
new ToolbarItem(
sort_by_location_string,
"mow.png",
SortByLocation,
ToolbarItemOrder.Secondary, 0)
);
list.Add(
new ToolbarItem(
sort_by_name_string,
"mow.png",
SortByName,
ToolbarItemOrder.Secondary, 1)
);
list.Add(
new ToolbarItem(
sort_by_recent_string,
"mow.png",
SortByNewest,
ToolbarItemOrder.Secondary, 2)
);
list.Add(
new ToolbarItem(
sort_by_earliest_string,
"mow.png",
SortByOldest,
ToolbarItemOrder.Secondary, 3)
);
return list;
}
I need the 3 dots to show up on iOS.

ASP.NET MVC Google pie chart controller

I am looking a friends code to implement google charts into my mvc project.
I have a model that I am pulling data from:
public partial class HoursPerSite
{
public string SiteName { get; set; }
public Nullable<decimal> SiteHours { get; set; }
}
The chart has rendered and it looks good but the legend is showing SiteHours and not SiteName as I'd like it to.
Here is the controller part:
// HOLIDAY PIE START
ViewBag.msg = db.HoursPerSites.Count().ToString();
var query = from r in db.HoursPerSites
select new { Count = r.SiteHours, Value = r.SiteHours };
var result2 = query.ToList();
var datachart2 = new object[result2.Count];
int l = 0;
foreach (var i in result2)
{
datachart2[l] = new object[] { i.Value.ToString(), i.Count };
l++;
}
string datastr2 = JsonConvert.SerializeObject(datachart2, Formatting.None);
ViewBag.dataj2 = new HtmlString(datastr2);
// HOLIDAY PIE END
I'd like it so the pie chart legend/key shows the site not the hours.
Not sure but is this:
select new { Count = r.SiteHours, Value = r.SiteHours };
Not supposed to be this: (SiteName):
select new { Count = r.SiteHours, Value = r.SiteName };
Also, your naming is very bad if I may say. That will not make your future work easier. Try naming your variables and obejects more specifically.
EDIT:
You can make use of Regions instead of code comments for example which will make seperation/ordering/viewing of code parts/sections much easier
Naming your variables better will make your life but also other
people working on/with your code easier
I would change your current code to this:
Please note that I don't have any editor and that there could be syntax errors
#region Holiday Pie Chart
ViewBag.msg = db.HoursPerSites.Count().ToString();
var queryHoursPerSites = from r in db.HoursPerSites
select new { Count = r.SiteHours, Value = r.SiteHours };
var resultsQueryHoursPerSites = queryHoursPerSites.ToList(); // or HoursPerSitesCollection
var holidayPieChart = new object[resultsQueryHoursPerSites.Count];
int counter = 0; //
foreach (var record in resultsQueryHoursPerSites)
{
holidayPieChart[counter] = new object[] { record.Value.ToString(), record.Count };
counter++;
}
string deserialisedResults = JsonConvert.SerializeObject(holidayPieChart, Formatting.None);
// no idea what dataj2 is here ...
ViewBag.dataj2 = new HtmlString(deserialisedResults);
#endregion
I am sure there is even more to "improve" or "change" but that would in my opinion already be an improvement.
I am sure others can elaborate even better on what I am suggesting here :)

How to list all the rows of a Gtk.Treeview

I'm having trouble grasping the use of GTK's TreeView and so I am running through some examples I have found online. Putting them together I am unable to work out how to extract the information in the view. I am operating the TreeView as a simple List with columns for the presentation of tabled data.
I am getting confused between the roles of models, stores and the actual treeview itself.
I am working from the example here
using System;
using System.Collections;
using Gtk;
public class Actress
{
public string Name;
public string Place;
public int Year;
public Actress(string name, string place, int year)
{
Name = name;
Place = place;
Year = year;
}
}
public class SharpApp : Window
{
ListStore store;
Statusbar statusbar;
enum Column
{
Name,
Place,
Year
}
Actress[] actresses =
{
new Actress("Jessica Alba", "Pomona", 1981),
new Actress("Sigourney Weaver", "New York", 1949),
new Actress("Angelina Jolie", "Los Angeles", 1975),
new Actress("Natalie Portman", "Jerusalem", 1981),
new Actress("Rachel Weissz", "London", 1971),
new Actress("Scarlett Johansson", "New York", 1984)
};
public SharpApp() : base ("ListView")
{
BorderWidth = 8;
SetDefaultSize(350, 250);
SetPosition(WindowPosition.Center);
DeleteEvent += delegate { Application.Quit(); };
VBox vbox = new VBox(false, 8);
ScrolledWindow sw = new ScrolledWindow();
sw.ShadowType = ShadowType.EtchedIn;
sw.SetPolicy(PolicyType.Automatic, PolicyType.Automatic);
vbox.PackStart(sw, true, true, 0);
store = CreateModel();
TreeView treeView = new TreeView(store);
treeView.RulesHint = true;
treeView.RowActivated += OnRowActivated;
sw.Add(treeView);
AddColumns(treeView);
statusbar = new Statusbar();
vbox.PackStart(statusbar, false, false, 0);
Add(vbox);
ShowAll();
}
void OnRowActivated (object sender, RowActivatedArgs args) {
TreeIter iter;
TreeView view = (TreeView) sender;
if (view.Model.GetIter(out iter, args.Path)) {
string row = (string) view.Model.GetValue(iter, (int) Column.Name );
row += ", " + (string) view.Model.GetValue(iter, (int) Column.Place );
row += ", " + view.Model.GetValue(iter, (int) Column.Year );
statusbar.Push(0, row);
}
// *** if I can dump treeview to the console here I'll be happy ***
// *** I'd prefer a foreach or do/while ***
}
void AddColumns(TreeView treeView)
{
CellRendererText rendererText = new CellRendererText();
TreeViewColumn column = new TreeViewColumn("Name", rendererText,
"text", Column.Name);
column.SortColumnId = (int) Column.Name;
treeView.AppendColumn(column);
rendererText = new CellRendererText();
column = new TreeViewColumn("Place", rendererText,
"text", Column.Place);
column.SortColumnId = (int) Column.Place;
treeView.AppendColumn(column);
rendererText = new CellRendererText();
column = new TreeViewColumn("Year", rendererText,
"text", Column.Year);
column.SortColumnId = (int) Column.Year;
treeView.AppendColumn(column);
}
ListStore CreateModel()
{
ListStore store = new ListStore( typeof(string),
typeof(string), typeof(int) );
foreach (Actress act in actresses) {
store.AppendValues(act.Name, act.Place, act.Year );
}
return store;
}
public static void Main()
{
Application.Init();
new SharpApp();
Application.Run();
}
}
An array of actresses is created at the top of the code, and that is used to populate a ListStore (towards the end of the code) that is in turn used to populate the TreeView.
I want to iterate over the treeview's data and update the columns within it.
To this end, since OnRowActivated is a nice place to dump information, I'd like to dump out the entire treeview contents to the console when a node is selected.
Any help in guiding me to get this done (and hopefully understanding it in the process) would be appreciated.
Whilst certainly not elegant I found the answer which also updates some of the data in the model. I'd be happy if anyone could improve upon this.
TreeIter iter;
TreeModel model = tv.Model;
if (model.GetIterFirst(out iter))
{
do
{
newYear = ModifyYear((string)model.GetValue(iter, (int)Column.Year));
Console.WriteLine("Updating: {0} -- {1} {2}",
(string)model.GetValue(iter, (int)Column.Name),
model.GetValue(iter, (int)Column.Year),
newYear );
model.SetValue(iter, (int)Column.Year, (int)newYear);
} while (model.IterNext(ref iter));
}

Adding subsequent months on x-axis using Live Charts

private int SumOfNodes()
{
ManufacturingDataModel MDM = new ManufacturingDataModel();
Test t = new Test(MDM);
List<Hardware> SumOfHardware = t.GetHardware().FindAll(x => x.Nodes != 0);
int SumOfNodes = 0;
foreach (Hardware i in SumOfHardware )
{
SumOfNodes += i.Nodes;
}
return SumOfNodes;
}
private int SumOfRepeaters()
{
ManufacturingDataModel MDM = new ManufacturingDataModel();
Test t = new Test(MDM);
List<Hardware> SumOfHardware = t.GetHardware().FindAll(x => x.Repeaters != 0);
int SumOfRepeaters = 0;
foreach (Hardware i in SumOfHardware)
{
SumOfRepeaters += i.Repeaters;
}
return SumOfRepeaters;
}
private int SumOfHubs()
{
ManufacturingDataModel MDM = new ManufacturingDataModel();
Test t = new Test(MDM);
List<Hardware> SumOfHardware = t.GetHardware().FindAll(x => x.Hubs != 0);
int SumOfHubs= 0;
foreach (Hardware i in SumOfHardware)
{
SumOfHubs += i.Hubs;
}
return SumOfHubs;
}
private string Month()
{
DateTime now = DateTime.Now;
string month = DateTime.Now.ToString("MMMM");
return month;
}
private void DisplayData()
{
SeriesCollection = new SeriesCollection
{
new ColumnSeries
{
Title = "Nodes",
Values = new ChartValues<int> { SumOfNodes() }
},
};
SeriesCollection.Add
(
new ColumnSeries
{
Title = "Repeaters",
Values = new ChartValues<int> { SumOfRepeaters() }
}
);
SeriesCollection.Add
(
new ColumnSeries
{
Title = "Hubs",
Values = new ChartValues<int> { SumOfHubs() }
}
);
Labels = new[] { Month() };
Formatter = value => value.ToString("N");
DataContext = this;
}
enter image description here
At this points I've managed to create an app that adds/removes and updates my items on my database. I'm also planning to add some stats (Started off with graph visualisation) but I'm facing an issue.
I want to seperate columns based on months. So for example as seen by the image attached no matter how many items i add , remove or update the total amount for each item is added to Decemeber. But when January comes any newly added modification to the quantity of my items I would like to see adjacent to the Decemeber one.
P.S.: There is alot of code repitition which will accounted for later on.
I've managed to put something together regarding my answer above which may be usefull for someone in the future
What I've done was to
1) Get my data from my db.
2) Find the Month of interest using LINQ queries **
instead of selecting the items (i.e repeaters, nodes)
**
3) By doing so it also accounts for the items I'm interested in during the month of interest.
4) Do an incremental foreach loop as shown in my code above.
5) Change the methodd i want to display (i.e DisplayData to DisplayDecemberData) and use in the same way as above.
6) Create further methods for the subsequent months and just add the additional information in the ChartValues object.
See Below
private int DecemberNodes()
{
ManufacturingDataModel MDM = new ManufacturingDataModel();
Test t = new Test(MDM);
List<Hardware> decembernodes = t.GetHardware().FindAll(x => x.Date.Month==12);
int DecemberSumOfNodes = 0;
foreach (Hardware i in decembernodes)
{
DecemberSumOfNodes += i.Nodes;
}
return DecemberSumOfNodes;
}
private int JanuaryNodes()
{
ManufacturingDataModel MDM = new ManufacturingDataModel();
Test t = new Test(MDM);
List<Hardware> januarynodes = t.GetHardware().FindAll(x => x.Date.Month==01);
int JanuarySumOfNodes = 0;
foreach (Hardware i in januarynodes)
{
JanuarySumOfNodes += i.Nodes;
}
private void DisplayDecemberData()
{
SeriesCollection = new SeriesCollection
{
new ColumnSeries
{
Title = "Nodes",
Values = new ChartValues<int> { DecemberNodes() }
},
};
private void DisplayJanuaryData()
{
SeriesCollection = new SeriesCollection
{
new ColumnSeries
{
Title = "Nodes",
**Values = new ChartValues<int> { DecemberNodes(), JanuaryNodes() }**
},
};
There is some code repetition and I'm pretty sure there is a more code concise way of actually doing it but for now this seems to do the trick. When I simplify the code i will post it.

Updating TreeView after changing CellRendererCombo (Gtk#)

Could somebody point me in the right direction on how to update a Gtk.TreeView after changing a CellRendererCombo in Gtk#?
Since the only example I found was in Python, I tried to port the example to C#, but without success so far.
The Python example is here: http://learngtk.org/pygtk-tutorial/cellrenderercombo.html
In the code below I am having difficulties with the method ComboChanged.
After changing the value in the combobox (by selecting a different value) and placing the focus outside of the combobox, the value does not change.
using System;
using Gtk;
using System.Collections.Generic;
public partial class MainWindow: Gtk.Window
{
public MainWindow (): base (Gtk.WindowType.Toplevel)
{
Build ();
var tvComboBox = InitTreeViewWithComboBox ();
var vbox = new Gtk.VBox ();
vbox.PackStart (tvComboBox, true, true, 0);
this.Add (vbox);
this.ShowAll ();
}
// adopted from http://learngtk.org/pygtk-tutorial/cellrenderercombo.html
ListStore liststore_hardware;
ListStore liststore_manufacturers;
private TreeView InitTreeViewWithComboBox ()
{
liststore_manufacturers = new Gtk.ListStore(typeof (string));
var manufacturers = new List<string> {"Sony", "LG", "Panasonic", "Toshiba", "Nokia", "Samsung"};
foreach (var item in manufacturers) {
liststore_manufacturers.AppendValues (item);
}
liststore_hardware = new Gtk.ListStore(typeof (string), typeof (string));
liststore_hardware.AppendValues ("Television", "Samsung");
liststore_hardware.AppendValues ("Mobile Phone", "LG");
liststore_hardware.AppendValues ("DVD Player", "Sony");
var treeview = new Gtk.TreeView ();
treeview.Model = liststore_hardware;
var column_text = new TreeViewColumn { Title = "Text" };
var column_combo = new TreeViewColumn { Title = "Combo" };
treeview.AppendColumn (column_text);
treeview.AppendColumn (column_combo);
var cellrenderer_text = new CellRendererText ();
column_text.PackStart (cellrenderer_text, false);
column_text.AddAttribute (cellrenderer_text, "text", 0);
var cellrenderer_combo = new CellRendererCombo ();
cellrenderer_combo.Editable = true;
cellrenderer_combo.Model = liststore_manufacturers;
cellrenderer_combo.TextColumn = 0;
column_combo.PackStart (cellrenderer_combo, false);
column_combo.AddAttribute (cellrenderer_combo, "text", 1);
cellrenderer_combo.Edited += ComboChanged;
return treeview;
}
void ComboChanged (object o, EditedArgs args)
{
// Not really sure what to do here....
/*
var crc = o as CellRendererCombo;
TreeIter iter; // index within the combobox
if (!crc.Model.GetIterFirst (out iter)) {
return;
}
crc.Model.SetValue (iter, 0, args.NewText);
liststore_hardware.SetValue (iterHardware, 1, args.NewText);
*/
}
Going through the API a bit more I found the solution...:
void ComboChanged (object o, EditedArgs args)
{
TreeSelection selection = treeview.Selection;
TreeIter iter;
if (!selection.GetSelected (out iter)) {
return;
}
liststore_hardware.SetValue (iter, 1, args.NewText);
}

Categories