gtk#, TreeView, CellRendererSpin: Spin buttons not visible & Custom CellRenderers - c#

I am trying to use a spin button within my TreeView.
It as added like this:
Gtk.TreeViewColumn adjustColumn = new Gtk.TreeViewColumn();
adjustColumn.Title = "";
Gtk.CellRendererSpin adjustCell = new Gtk.CellRendererSpin();
adjustCell.Digits = 0;
adjustCell.Adjustment = new Adjustment(0, 0, 99, 1, 99, 99);
adjustCell.Editable = true;
adjustCell.Visible = true;
adjustCell.Sensitive = true;
adjustCell.Mode = CellRendererMode.Editable;
adjustColumn.PackEnd(adjustCell, true);
adjustColumn.SetCellDataFunc(adjustCell, new Gtk.TreeCellDataFunc(RenderAdjuster));
treeView.AppendColumn(adjustColumn);
And inside the rendering function the following is done:
(cell as Gtk.CellRendererSpin).Width = 30;
(cell as Gtk.CellRendererSpin).Height = 20;
(cell as Gtk.CellRendererSpin).Text = "" + (cell as Gtk.CellRendererSpin).Adjustment.Value;
This does render the value, but the spin buttons are not visible! They only become visible once the user clicks the value. That is absolutely ridiculous, as there is no way the user will know that the cell is editable other than randomly clicking in it, especially since there are other values in the row that are not editable.
So my first question is, how can I make those spin buttons always visible?
Could this be done with a custom CellRenderer?
I would be thankful for an example of how to create my own, actually working, spin button cell renderer. Unfortunately, custom cell renderers are an undocumented mystery (as almost anything in gtk# ;) ). And all you can find to them are examples that draw Cairo rectangles, etc. themselves. There must be an easier way where can you simply put any widget into that renderer, and listen to clicks, etc. and simply render the widget when the cell is rendered.
An example for a custom CellRenderer that simply displays a button (that can listen to clicks) would also be fine as I could at least "fake" a SpinButton, by having three columns with a text, a "+"-Button and a "-"-Button.

Related

How to prevent text box from gaining focus unless clicked?

I have a WinForms application that has a TextBox control (search box) at the top of it. This TextBox is constantly receiving focus during normal application use, and it is very distracting.
I would like the TextBox to only receive the focus if the user explicitly clicks on it.
I can think of a couple rather complicated ways to accomplish this:
Change an image of a text box into a text box when clicked
Keep track of mouse clicks and shift the focus away based on mouse state
Is there something simpler that I can do to accomplish this?
Edit to add better description of problem based on new understanding
Based on the answers that I have received, I now have a bit of a better understanding of what was causing this problem. As the user interacted with my application, various actions would cause controls to either be disabled or to completely disappear. If one of these controls happened to have the focus at the time, then the next control in the tab order would receive the focus.
I don't know what was the "next control" before I added the text box in question. The application has hundreds of controls on screen at any given time, and I'm pretty sure that tab order was never intentionally defined. Whatever it was before, it was innocuous. After adding the search text box, it seemed like that control would always end up with the focus.
Here is a very simple example that demonstrates what was happening:
public class Form1 : Form
{
public Form1()
{
var button = new Button
{
Location = new System.Drawing.Point(159, 67),
Size = new System.Drawing.Size(75, 23),
TabIndex = 0,
Text = #"Click me"
};
button.Click += (sender, args) => button.Enabled = false;
var textBox = new TextBox
{
Location = new System.Drawing.Point(159, 142),
Name = "textBox1",
Size = new System.Drawing.Size(174, 20),
TabIndex = 1
};
SuspendLayout();
ClientSize = new System.Drawing.Size(486, 392);
Controls.Add(textBox);
Controls.Add(_button);
ResumeLayout(false);
PerformLayout();
}
}
After starting the application, clicking on the button will force the text box to get the focus, since it is the next in the tab order. As mentioned by Handbag Crab in the accepted answer, this behavior can be avoided by setting TabStop = false on the text box.
textBox1.TabStop = false;
The above should stop it receiving focus from tabbing.
Subclass the TextBox and over WndProc function to capture the focus message and handle it. Maybe something like this:
if (m.Msg == WM_MOUSEACTIVATE) {
m.Result = (IntPtr)MA_NOACTIVATEANDEAT;
return;
}
base.WndProc(ref m);

windows forms can't add more components

I want to build a form that has 100 label and 100 text box
what I did is:
add new form
add panel to that form using drag and drop
change the dock property of that panel to fill
change the AutoScroll property to True
start adding the labels and text boxes using drag and drop
The problem
I added like 40 labels and text boxes but I can't add any more because I can't expand the form nor the label vertically.
Note
I can minimize the size of the panel and a vertical scroll bar appears. (maybe this information helps you to help me).
A data entry window with that many text boxes is going to require scrolling. So set the Panel's AutoScrollMinSize property to, say, (1000, 1000) as a first guess. You'll see the scrollbars appear. They work at design time as well, allowing you to scroll the panel and place the controls. High odds you should be using a DataGridView btw.
Something that needs to be said: the odds that you can get a human to enter 100 data items without any mistake are very close to zero. A very frustrating job for the hapless user, it will take him 10 or more minutes only to arrive at failure. Create a user friendly UI, one that partitions the data entry job in small steps that can be successfully completed. Automatically solves this problem as well.
Set parent form's properties AutoSize and AutoScroll to true. Then disable docking for your panel. This way you can set any size to panel and scroll form contents to add new controls. When panel design is done, set docking to Fill again.
Or you can set position for newly added controls using Properties panel. This will move controls to appropriate position on the panel.
This is a sample method I've used to add an unknown number of controls to a form. The trick is a FlowLayoutPanel.
As has been said before: you don't want 100 manually added controls on your page.
private void AddMappingControls() {
HeaderFlowLayoutPanel.Controls.Clear();
MappingFlowLayoutPanel.Controls.Clear();
Label sourceHeaderLabel = new Label();
sourceHeaderLabel.Text = "Velden in Excel (bron)";
sourceHeaderLabel.Name = "BronLabel";
sourceHeaderLabel.Width = MappingFlowLayoutPanel.Width / 2 - 20;
HeaderFlowLayoutPanel.Controls.Add(sourceHeaderLabel);
Label destinationHeaderLabel = new Label();
destinationHeaderLabel.Text = "Velden in Word sjabloon (bestemming)";
destinationHeaderLabel.Name = "BestemmingLabel";
destinationHeaderLabel.Width = MappingFlowLayoutPanel.Width / 2 - 20;
HeaderFlowLayoutPanel.Controls.Add(destinationHeaderLabel);
foreach (string destination in this.destinationFields) {
ComboBox sourceFieldComboBox = new ComboBox();
sourceFieldComboBox.BindingContext = new System.Windows.Forms.BindingContext();
sourceFieldComboBox.DropDownStyle = ComboBoxStyle.DropDownList;
//sourceFieldComboBox.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
sourceFieldComboBox.Name = destination + "ComboBox";
sourceFieldComboBox.ValueMember = destination;
sourceFieldComboBox.DataSource = this.sourceFields;
sourceFieldComboBox.Width = MappingFlowLayoutPanel.Width / 2 - 20;
MappingFlowLayoutPanel.Controls.Add(sourceFieldComboBox);
Label nameLabel = new Label();
nameLabel.Text = destination;
nameLabel.Name = destination + "Label";
nameLabel.Width = MappingFlowLayoutPanel.Width / 2 - 20;
MappingFlowLayoutPanel.Controls.Add(nameLabel);
}
}
I meant exactly the same as MeanGreen but he was first. I have created sample solution: https://www.amazon.com/clouddrive/share?s=i9N7raPPQPEjOdHPRn99uE

control to show steps to do something in winforms

i want to show steps on how to cook something in winform c# .net as steps. Something like a set of text area would be nice but:
-> list box considers the whole string of one step as one item so user needs to scroll horizontally to view the whole step.
-> datagridview is also not suitable as i want the text to word wrapped.
i also want the user to be able to edit the step.
any suggestions of custom control would be nice.
Maybe a wizard like app would be suitable for you. AFAIK there's no native wizard control in C# but you could implement one using tabs or using one of many in the web.
A multi line text box will do the job great. just take a simple text box and do the following to it, and it will turn to a text area:
TextBox listBoxNewInput = new TextBox();
//Initialize label's property
listBoxNewInput.Multiline = true;
// Add vertical scroll bars to the TextBox control.
listBoxNewInput.ScrollBars = ScrollBars.Vertical;
// Allow the RETURN key in the TextBox control.
listBoxNewInput.AcceptsReturn = true;
// Allow the TAB key to be entered in the TextBox control.
listBoxNewInput.AcceptsTab = true;
// Set WordWrap to true to allow text to wrap to the next line.
listBoxNewInput.WordWrap = true;
listBoxNewInput.Width = 315;
listBoxNewInput.Height = 150;
listBoxNewInput.DoubleClick += new EventHandler(listBoxNewInput_DoubleClick);
flowLayoutPanel1.FlowDirection = FlowDirection.TopDown;
flowLayoutPanel1.Controls.Add(labelInput);
flowLayoutPanel1.FlowDirection = FlowDirection.TopDown;
flowLayoutPanel1.Controls.Add(list
BoxNewInput);

C# equivalent of Delphi's DisableControls/EnableControls

What is the C# equivalent of Delphi's DisableControls/EnableControls methods (used to disable updating of databound controls while iterating through the underlying dataset)? I have googled for half an hour and did not find an answer...
I have a list box and a rich edit box bound to a binding source, but I need to do an operation that iterates through the entire dataset, and both controls get updated as I move through the underlying dataset. In Delphi this is easy enough: enclose the block that does the iteration between DisableControls and EnableControls. I can't find the C#/.NET equivalent, and I have looked really hard!
IIRC, setting Enabled to false does not prevent the controls from reacting to data changes in WinForms.
Collection-bound controls like the ListBox typically have methods BeginUpdate() and EndUpdate() which temporarily disable visual updates.
Also, the property mentioned by DarkSquirrel might be worth a look
I don't have access to Visual Studio right now, so I can't test this, but look through the methods for the control instance. Code such as:
// set the Enabled property of
// the controls to False; this should
// disable the controls for user access
listBox.Enabled = False;
richEditBox.Enabled = False;
// perform iteration
// and other operations
// set the Enabled property back
// to True
listBox.Enabled = True;
richEditBox.Enabled = True;
The exact name of the property may differ slightly, but I'm pretty sure that this is what it is.
I assume you are using WinForms, in that case you can try using the methods SuspendLayout/ResumeLayout.
Code sample from MSDN:
private void AddButtons()
{
// Suspend the form layout and add two buttons.
this.SuspendLayout();
Button buttonOK = new Button();
buttonOK.Location = new Point(10, 10);
buttonOK.Size = new Size(75, 25);
buttonOK.Text = "OK";
Button buttonCancel = new Button();
buttonCancel.Location = new Point(90, 10);
buttonCancel.Size = new Size(75, 25);
buttonCancel.Text = "Cancel";
this.Controls.AddRange(new Control[]{buttonOK, buttonCancel});
this.ResumeLayout();
}
So far I know, you don't need to Disiable/EnableControls in C#, since this type of DataSet doesn't work with a current cursor, like Delphi TDataSets.

trying to add/remove controls to a form

plz keep in mind I'm very noobish...
What I'm trying to do is add "blips" to my form. I have a calculation that determines where all these "blips" will be, which is plotted on a graph. the solution determines that the coordinates are "blipHours, blipAltitude"
I want to somehow add small dots to my form at these locations. At first I was going to create something to be my "blips" but then I realized that I want it so small that I could just use an empty picture box with the background color what I want (I know this isn't the best way but I'm still very new to this).
I've created the code that will add the blip
PictureBox blip = new PictureBox();
blip.Location = new Point(blipHours, blipAltitude);
blip.Size = new Size(6, 6);
blip.BackColor = System.Drawing.Color.Lime;
blip.Text = "";
blip.Name = callsign;
this.Controls.Add(blip);
It adds the blip, but it always adds it underneath other controls. Is there a way to make it add the new blip on top of everything else so that it's visible?
my second question is how do I remove all of the blips that get created at once with the click of a button?
An alternative to nobugz' answer is to change the Z-order of your controls via the Form.Controls.SetChildIndex method:
this.Controls.Add(blip);
this.Controls.SetChildIndex(blip, 0);
You can use .AddAt to set its position in the list of controls.

Categories