Gtk.TreeView editable columns in Vala - treeview

Is there any simple way how to make a Gtk.Treeview updating its columns on edit?
I build the Treeview based on a Gtk.ListStore model. I initialize the cells like this:
Gtk.CellRendererText valueCells = new Gtk.CellRendererText ();
valueCells.editable = true;
tree_view.insert_column_with_attributes (-1, "Key", valueCells, "text", 0);
tree_view.insert_column_with_attributes (-1, "Value", valueCells, "text", 1);
I'm now able to select and edit the columns until I exit the Selection. Neither the TreeView nor the ListStore is updated. Tried several solutions I found written in different languages but nothing worked. I understood i have to update the model, but couldn't figure out how to find the reference to that.. Do I miss something essential? O.o

You have to connect the edited signal to get notified of changes made by the user, here is a complete example:
class MainWindow : Gtk.Window {
public MainWindow () {
Gtk.TreeView tree_view = new Gtk.TreeView ();
setup_treeview (tree_view);
add(tree_view);
}
private void setup_treeview (Gtk.TreeView view) {
var listmodel = new Gtk.ListStore (4, typeof (string), typeof (string),
typeof (string), typeof (string));
view.set_model (listmodel);
view.insert_column_with_attributes (-1, "Account Name", new Gtk.CellRendererText (), "text", 0);
view.insert_column_with_attributes (-1, "Type", new Gtk.CellRendererText (), "text", 1);
var cell = new Gtk.CellRendererText ();
cell.set ("foreground_set", true);
cell.editable = true;
cell.edited.connect ((path, new_text) => {
stdout.printf (path + "\n");
stdout.printf (new_text + "\n");
stdout.flush ();
});
view.insert_column_with_attributes (-1, "Balance", cell, "text", 2, "foreground", 3);
Gtk.TreeIter iter;
listmodel.append (out iter);
listmodel.set (iter, 0, "My Visacard", 1, "card", 2, "102,10", 3, "red");
listmodel.append (out iter);
listmodel.set (iter, 0, "My Mastercard", 1, "card", 2, "10,20", 3, "red");
}
}
int main (string[] args) {
Gtk.init (ref args);
MainWindow window = new MainWindow ();
window.title = "Tree View test";
window.border_width = 10;
window.window_position = Gtk.WindowPosition.CENTER;
window.set_default_size (350, 200);
window.destroy.connect (Gtk.main_quit);
window.show_all ();
Gtk.main ();
return 0;
}
The important bit is here:
var cell = new Gtk.CellRendererText ();
cell.editable = true;
cell.edited.connect ((path, new_text) => {
stdout.printf (path + "\n");
stdout.printf (new_text + "\n");
stdout.flush ();
});
It will print the path and the new_text of the modified cell to the command line.
All you have to do now is to update the model accordingly.

using Gtk;
public class viewWindow:Gtk.Window {
public viewWindow() {
this.destroy.connect(Gtk.main_quit);
set_default_size(200,150);
Gtk.ListStore list_store=new Gtk.ListStore(1, typeof(string));
Gtk.TreeIter iter;
list_store.append(out iter);
list_store.set(iter, 0, "Earth");
list_store.append(out iter);
list_store.set(iter, 0, "Mars");
Gtk.TreeView view=new TreeView.with_model(list_store);
this.add(view);
Gtk.CellRendererText cell=new Gtk.CellRendererText();
view.insert_column_with_attributes(-1, "Planet", cell, "text", 0);
cell.editable = true;
cell.edited.connect ((path, data) => {
Gtk.TreePath tPath = new Gtk.TreePath.from_string(path);
var model = view.get_model();
var res = model.get_iter(out iter, tPath);
if (res == true) {
list_store.set(iter, 0, data);
}
});
}
public static int main(string[] args) {
Gtk.init(ref args);
var view = new viewWindow();
view.show_all();
Gtk.main();
return 0;
}
}

Related

Carousel View in Xamarin Forms NOT Loading different Templates

public DataTemplate CreateQuestionAnswerRadioButtonTemplate(string question, List<string> answers){
DataTemplate template = new DataTemplate(() =>
{
StackLayout parentLayout = new StackLayout()
{
Padding = new Thickness(20, 20, 20, 20),
HeightRequest = 500,
};
ScrollView surveyScrollView = new ScrollView()
{
Orientation = ScrollOrientation.Vertical,
};
StackLayout questionLayout = new StackLayout()
{
Padding = new Thickness(5, 5, 5, 5),
HeightRequest = 500,
};
Label questLabel = new Label();
questLabel.Text = question;
questLabel.TextColor = Color.FromHex("#EF4D80");
questLabel.FontAttributes = FontAttributes.Bold;
questLabel.FontSize = 18;
BindableRadioGroup radioGroup = new BindableRadioGroup(false);
radioGroup.ItemsSource = answers;
questionLayout.Children.Add(questLabel);
questionLayout.Children.Add(radioGroup);
surveyScrollView.Content = questionLayout;
parentLayout.Children.Add(surveyScrollView);
return parentLayout;
});
return template;
}
Adding these Data Templates to a List.
new CarouselView
{
Margin = new Thickness(0, 20, 0, 0),
ItemsSource = dataTemplates,
ItemTemplate = dataTemplates[0],
};
Now when I swipe the Carousel, How do I load dataTemplates[1 or 2 or 3] ??
I have a Next Button in which in am setting the item source of the Carousel View to dataTemplates[1] but the template does not get updated
Pls Suggest the right approach ?
dataTemplates = new List<DataTemplate>();
dataTemplates.Add(CreateQuestionAnswerRadioButtonTemplate(Constants.SurveyQuestion_1, SurveyQuestion_1_Answers));
dataTemplates.Add(CreateQuestionAnswerRadioButtonTemplate(Constants.SurveyQuestion_3, SurveyQuestion_3_Answers));
dataTemplates.Add(CreateQuestionAnswerRadioButtonTemplate(Constants.SurveyQuestion_4, SurveyQuestion_4_Answers));
dataTemplates.Add(CreateQuestionAnswerRadioButtonTemplate(Constants.SurveyQuestion_5, SurveyQuestion_5_Answers));
You need a DataTemplateSelector for your CarouselView.
in your code behind of the page:
new CarouselView
{
Margin = new Thickness(0, 20, 0, 0),
ItemsSource = dataTemplates,
ItemTemplate = new SurveyDataTemplateSelector()
};
SurveyDataTemplateSelector
DataTemplate survey1Template;
DataTemplate survey3Template;
DataTemplate survey4Template;
DataTemplate survey5Template;
public SurveyDataTemplateSelector()
{
survey1Template = CreateQuestionAnswerRadioButtonTemplate(Constants.SurveyQuestion_1, SurveyQuestion_1_Answers);
survey3Template = CreateQuestionAnswerRadioButtonTemplate(Constants.SurveyQuestion_3, SurveyQuestion_3_Answers);
survey4Template = CreateQuestionAnswerRadioButtonTemplate(Constants.SurveyQuestion_4, SurveyQuestion_4_Answers);
survey5Template = CreateQuestionAnswerRadioButtonTemplate(Constants.SurveyQuestion_5, SurveyQuestion_5_Answers);
}
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
// Here you define which DataTemplate is selected, for example:
if (item == null)
{
return null;
}
SurveyAnswers answers = item as SurveyAnswers;
if (answers.question == 1)
{
return survey1Template;
}
else if (answers.question == 3)
{
return survey3Template;
}
else if (answers.question == 4)
{
return survey4Template;
}
else if (answers.question == 5)
{
return survey5Template;
}
return null;
}
Check this link for a good documentation by Xamarin: https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/templates/data-templates/selector/

How to Add Content Page to Segment Control in IOS Xamarin.Forms

I have used Segmented Control in my application. I don't know how to add two content pages to Segment control like a tabbed page. I have attached the sample file. Please give any suggestion Link for Sample Application
Sample Code:
public partial class SamplePage : ContentPage
{
SegmentedControl segControl;
SegmentedControlOption optionOne;
SegmentedControlOption optionTwo;
public SamplePage()
{
segControl = new SegmentedControl();
optionOne = new SegmentedControlOption();
optionTwo = new SegmentedControlOption();
optionOne.Text = "One";
optionTwo.Text = "Two";
segControl.Children.Add(optionOne);
segControl.Children.Add(optionTwo);
var stack = new StackLayout()
{
VerticalOptions = LayoutOptions.StartAndExpand,
HorizontalOptions = LayoutOptions.CenterAndExpand,
Children = { segControl }
};
this.Content = stack;
}
}
ScreenShot Attached
Just some suggestions and explanations.
We can't put a ContentPage inside another ContentPage
It's better to use ContentView instead of ContentPage
Grid is more recommended in this scenario , since it fills with the whole Screen.
Use ValueChanged event to change the view dynamically.
Code :
Page
public partial class SegmentedAppPage : ContentPage
{
SegmentedControl segControl;
SegmentedControlOption scOptionOne;
SegmentedControlOption scOptionTwo;
Grid grid;
View1 view1 = new View1();
View2 view2 = new View2();
public SegmentedAppPage()
{
InitializeComponent();
segControl = new SegmentedControl();
segControl.SelectedValue = "One";
scOptionOne = new SegmentedControlOption();
scOptionTwo = new SegmentedControlOption();
scOptionOne.Text = "One";
scOptionTwo.Text = "Two";
segControl.Children.Add(scOptionOne);
segControl.Children.Add(scOptionTwo);
grid = new Grid();
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Auto) });
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
grid.Children.Add(segControl, 0, 0);
grid.Children.Add(view1, 0, 1);
this.Content = grid;
segControl.ValueChanged += SegControl_ValueChanged;
}
private void SegControl_ValueChanged(object sender, EventArgs e)
{
SegmentedControl control = sender as SegmentedControl;
if(control.SelectedValue is "One")
{
grid.Children.Remove(view2);
grid.Children.Add(view1,0,1); //This line
}
else if (control.SelectedValue is "Two")
{
grid.Children.Remove(view1);
grid.Children.Add(view2, 0, 1); //This line
}
this.Content = grid;
}
}
ContentView
public class View1 : ContentView
{
public View1()
{
Content = new StackLayout
{
BackgroundColor = Color.Green,
Children = {
new Label { Text = "View1" }
}
};
}
}
To set default value on segmentedControl , modify code in SegmentedControlRenderers
protected override void OnElementChanged(ElementChangedEventArgs<SegmentedControl> e)
{
base.OnElementChanged(e);
var segmentedControl = new UISegmentedControl();
for (var i = 0; i < e.NewElement.Children.Count; i++)
{
segmentedControl.InsertSegment(e.NewElement.Children[i].Text, i, false);
}
segmentedControl.ValueChanged += (sender, eventArgs) => {
e.NewElement.SelectedValue = segmentedControl.TitleAt(segmentedControl.SelectedSegment);
};
segmentedControl.SelectedSegment = 0; // add this line
SetNativeControl(segmentedControl);
}
Test

ZXing(Zebra Xing) Unable to scan/ detect the barcode in Xamarin iOS

I posted couple other questions in regards to Zxing please DONT mark it duplicate just because they are about Zxing..
So, in my Xamarin iOS app, I am using Zxing to detect the barcode. I am using https://github.com/Redth/ZXing.Net.Mobile/tree/master/Samples/iOS as example.
I am using a subview to scan for barcodes. The custom overlay n everything works fine but it is unable to detect the barcode when I'm trying to scan.
Can anyone please help me out where I'm doing wrong or missing something.
CODE
public UIView camView;
AVCaptureScannerView scannerView;
UIActivityIndicatorView loadingView;
UIView loadingBg;
UIView topBg;
UIView bottomBg;
MobileBarcodeScanner scanner;
public event Action<ZXing.Result> OnScannedResult;
public MobileBarcodeScanningOptions ScanningOptions { get; set; }
public override void ViewDidLoad()
{
camView = new UIView(new CGRect(0, 0, this.View.Frame.Width, this.View.Frame.Height / 3)) { BackgroundColor = UIColor.Clear };
scanner = new MobileBarcodeScanner();
Root = new RootElement("ZXingDwatNet.Mobile") {
new Section {
camView
}
};
scannerView = new AVCaptureScannerView(camView.Frame);
camView = scannerView;
loadingBg = camView;// new UIView(this.View.Frame) { BackgroundColor = UIColor.Purple, AutoresizingMask = UIViewAutoresizing.FlexibleDimensions };
loadingView = new UIActivityIndicatorView(UIActivityIndicatorViewStyle.White)
{
AutoresizingMask = UIViewAutoresizing.FlexibleMargins
};
loadingView.Frame = new CGRect((this.View.Frame.Width - loadingView.Frame.Width) / 4,
(this.View.Frame.Height - loadingView.Frame.Height) / 4,
loadingView.Frame.Width / 4,
loadingView.Frame.Height / 4);
loadingBg.AddSubview(loadingView);
View.AddSubview(loadingBg);
loadingView.StartAnimating();
this.View.InsertSubviewBelow(scannerView, loadingView);
this.View.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
}
void HandleScanResult(ZXing.Result result)
{
string msg = "";
if (result != null && !string.IsNullOrEmpty(result.Text))
msg = "Found Barcode: " + result.Text;
else
msg = "Scanning Canceled!";
this.InvokeOnMainThread(() =>
{
var av = new UIAlertView("Barcode Result", msg, null, "OK", null);
av.Show();
});
}
public override void ViewDidAppear(bool animated)
{
//scannerView.OnScannerSetupComplete += HandleOnScannerSetupComplete;
//camView = scannerView;
var options = new MobileBarcodeScanningOptions
{
AutoRotate = false,
UseFrontCameraIfAvailable = false,
TryHarder = true
};
ScanningOptions = options;
if (UIDevice.CurrentDevice.CheckSystemVersion(7, 0))
{
UIApplication.SharedApplication.StatusBarStyle = UIStatusBarStyle.Default;
SetNeedsStatusBarAppearanceUpdate();
}
else
UIApplication.SharedApplication.SetStatusBarStyle(UIStatusBarStyle.BlackTranslucent, false);
Console.WriteLine("Starting to scan...");
Task.Factory.StartNew(() =>
{
BeginInvokeOnMainThread(() => scannerView.StartScanning(result =>
{
//if (!ContinuousScanning)
//{
// Console.WriteLine("Stopping scan...");
// scannerView.StopScanning();
//}
var evt = this.OnScannedResult;
if (evt != null)
evt(result);
}, this.ScanningOptions));
});
}
void HandleOnScannerSetupComplete()
{
BeginInvokeOnMainThread(() =>
{
if (loadingView != null && loadingBg != null && loadingView.IsAnimating)
{
loadingView.StopAnimating();
UIView.BeginAnimations("zoomout");
UIView.SetAnimationDuration(2.0f);
UIView.SetAnimationCurve(UIViewAnimationCurve.EaseOut);
loadingBg.Transform = CGAffineTransform.MakeScale(2.0f, 2.0f);
loadingBg.Alpha = 0.0f;
UIView.CommitAnimations();
loadingBg.RemoveFromSuperview();
}
});
}

Issue with FlowListView Xamarin.Forms

I am using FlowListView To set gallery view in my xamarin forms application, with following code..
public class Page1 : ContentPage
{
public Page1()
{
ObservableCollection<ItemModel> List = new ObservableCollection<ItemModel>();
string[] images = {
"https://farm9.staticflickr.com/8625/15806486058_7005d77438.jpg",
"https://farm5.staticflickr.com/4011/4308181244_5ac3f8239b.jpg",
"https://farm8.staticflickr.com/7423/8729135907_79599de8d8.jpg",
"https://farm3.staticflickr.com/2475/4058009019_ecf305f546.jpg",
"https://farm6.staticflickr.com/5117/14045101350_113edbe20b.jpg",
"https://farm2.staticflickr.com/1227/1116750115_b66dc3830e.jpg",
"https://farm8.staticflickr.com/7351/16355627795_204bf423e9.jpg",
"https://farm1.staticflickr.com/44/117598011_250aa8ffb1.jpg",
"https://farm8.staticflickr.com/7524/15620725287_3357e9db03.jpg",
"https://farm9.staticflickr.com/8351/8299022203_de0cb894b0.jpg",
};
int number = 0;
for (int n = 0; n < 20; n++)
{
for (int i = 0; i < images.Length; i++)
{
number++;
var item = new ItemModel()
{
ImageUrl = images[i],
FileName = string.Format("image_{0}.jpg", number),
};
List.Add(item);
}
}
FlowListView listView = new FlowListView()
{
FlowColumnTemplate = new DataTemplate(typeof(ListCell)),
SeparatorVisibility = SeparatorVisibility.None,
HasUnevenRows = true,
FlowColumnMinWidth = 110,
FlowItemsSource = List,
};
listView.FlowItemTapped += (s, e) =>
{
var item = (ItemModel)e.Item;
if (item != null)
{
App.Current.MainPage.DisplayAlert("Alert", "Tapped {0} =" + item.FileName, "Cancel");
}
};
Content = new StackLayout
{
Children = {
listView
}
};
}
}
public class ItemModel
{
public string ImageUrl { get; set; }
public string FileName { get; set; }
}
public class ListCell : View
{
public ListCell()
{
CachedImage IconImage = new CachedImage
{
HeightRequest = 100,
Aspect = Aspect.Fill,
DownsampleHeight = 100,
DownsampleUseDipUnits = false,
LoadingPlaceholder = "image_loading.png",
ErrorPlaceholder = "image_error.png"
};
IconImage.SetBinding(CachedImage.SourceProperty, "ImageUrl");
Label NameLabel = new Label
{
Opacity = 0.5,
HorizontalOptions = LayoutOptions.Fill,
HorizontalTextAlignment = TextAlignment.Center,
VerticalOptions = LayoutOptions.End,
};
NameLabel.SetBinding(Label.TextProperty, "FileName");
Grid grd = new Grid
{
Padding = 3,
ColumnDefinitions = {
new ColumnDefinition { Width = new GridLength (1, GridUnitType.Star) },
},
RowDefinitions = {
new RowDefinition { Height=GridLength.Star},
},
};
grd.Children.Add(IconImage,0,0);
grd.Children.Add(NameLabel, 0, 1);
}
}
i added all the dependency of FlowListView, FFImage etc,
This above code just showing blank screen, Not displaying any data...
You're ListCell has nothing to show.
Append the existing lines to set the content to the grid in your custom ViewCell.
grd.Children.Add(IconImage,0,0);
grd.Children.Add(NameLabel, 0, 1);
Content = grd; <--- add this line
Also have you done the following as per advice from the author? i.e. You've added the nuget library to the platforms in addition to the PCL and added the corresponding initialisation code for the library?
You must add this line to your platform specific project (AppDelegate.cs, MainActivity.cs, etc) before you use FFImageLoading:
CachedImageRenderer.Init();
This is what I got in my IOS:
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
FFImageLoading.Forms.Touch.CachedImageRenderer.Init(); <---- this line
LoadApplication(new App());
return base.FinishedLaunching(app, options);
}
}

Cross-application drag and drop with Vala/GTK+ 3

How can I set a GTK+ 3 widget in Vala as a drag and drop target for external items? More specifically, I'd like to allow a user to drag movie files from a file manager into my application, so that I can get the dropped file's name, or if the user drags a directory, the filenames of the directory contents.
It is explained here:
https://laptrinhx.com/vala-9-drag-drop-3521859046/
using Gtk;
public class MainWindow : Gtk.Window
{
private Box vboxMain;
private ScrolledWindow swFiles;
private TreeView tvFiles;
private TreeViewColumn colName;
private const Gtk.TargetEntry[] targets = {
{"text/uri-list",0,0}
};
public static int main (string[] args)
{
Gtk.init(ref args);
var window = new MainWindow ();
window.show_all ();
Gtk.main();
return 0;
}
public MainWindow ()
{
this.title = "Drag files on this window";
this.window_position = WindowPosition.CENTER;
this.destroy.connect (Gtk.main_quit);
set_default_size (550, 400);
//vboxMain
vboxMain = new Box (Orientation.VERTICAL, 6);
vboxMain.margin = 6;
add (vboxMain);
//tvFiles
tvFiles = new TreeView();
//swFiles
swFiles = new ScrolledWindow(tvFiles.get_hadjustment (), tvFiles.get_vadjustment ());
swFiles.set_shadow_type (ShadowType.ETCHED_IN);
swFiles.set_size_request (550, 400);
swFiles.add(tvFiles);
vboxMain.add(swFiles);
//colName
colName = new TreeViewColumn();
colName.title ="File";
colName.expand = true;
CellRendererText cellName = new CellRendererText ();
colName.pack_start (cellName, false);
colName.set_attributes(cellName, "text", 0);
tvFiles.append_column(colName);
//inputStore
Gtk.ListStore store = new Gtk.ListStore (1, typeof (string));
tvFiles.model = store;
//connect drag drop handlers
Gtk.drag_dest_set (this,Gtk.DestDefaults.ALL, targets, Gdk.DragAction.COPY);
this.drag_data_received.connect(this.on_drag_data_received);
}
private void on_drag_data_received (Gdk.DragContext drag_context, int x, int y,
Gtk.SelectionData data, uint info, uint time)
{
//loop through list of URIs
foreach(string uri in data.get_uris ()){
string file = uri.replace("file://","").replace("file:/","");
file = Uri.unescape_string (file);
//add file to tree view
add_file (file);
}
Gtk.drag_finish (drag_context, true, false, time);
}
private void add_file(string file)
{
TreeIter iter;
Gtk.ListStore store = (Gtk.ListStore) tvFiles.model;
store.append (out iter);
store.set (iter, 0, file);
}
}
Build with valac dnd.vala --pkg gtk+-3.0

Resources