Microsoft Chart Controls Legend Item Ordering - mschart

I've got a chart with 8 series - call them S1 through S8. They're in order in the chart's list of series, and they're presented using custom legend items (Legend.CustomItems). Everything works fine, except there seems to be a bug with how items are displayed in the legend when the legend wraps around to a new line.
I'd like the items to be displayed in rows:
S1 S2 S3 S4
S5 S6 S7 S8
Unfortunately, it seems like when the legend detects that it's going to take two rows, it fills in vertically before horizontally, like so:
S1 S3 S5 S7
S2 S4 S6 S8
Is there any way to get the items arranged properly? Is this a bug with the controls?
var chart = new Chart();
// More chart setup
foreach(var s in chart.Series)
{
if (simpleLegend) chart.Legends[0].CustomItems.Add(s.Color, s.LegendText);
else
{
var legendItem = new LegendItem();
// Legend item customization
chart.Legends[0].CustomItems.Add(legendItem);
}
}
EDIT
To make it clear, the issue is with the layout of the legend items, not the order. Depending on the length of the legend items, I may end up with this layout:
S1 S3 S5 S7 S8
S2 S4 S6

You can arrange them in CustomizeLegend event.
Add OnCustomizeLegend="Chart1_CustomizeLegend" to your Chart markup or bind it in code behind. Then create handler:
protected void Chart1_CustomizeLegend(object sender, CustomizeLegendEventArgs e)
{
//change order of legend items
var items = e.LegendItems;
var item = items[1]; //s2
items.RemoveAt(1);
items.Insert(2, item);
item = items[1]; //after removing s2, s3 is now here
items.RemoveAt(1);
items.Insert(4, item);
//etc...
}
Or you can create some collection first and fill it by referencing existing legend items in desired order, then clearing LegendItems and inserting all items at once. I think you can write it in a way it will be valid for all items number, but I leave it to you ;).
More info: http://msdn.microsoft.com/en-us/library/dd488245.aspx
(I know this question is almost 2 years old but maybe someone with same problem (like me today) will find this helpful.)

Related

SwiftUI Make a list that shows only a certain amount of rows

I have recently started messing around with SwiftUI and so far it is great. I have however ecnountered a problem that I can't seem to find an answer to.
I am trying to create this design:
As you can see here is a tableview (a list) which rows have a smaller tableview (a list) inside them. The task was pretty simple while using IB, but with swiftUI I can't seem to find a way to limit the number of rows to only the amount I need or to manually set the lists height based on the number of rows (keep in mind those rows can also be variable in height).
My code so far only consist of creating the List and adding 2 test rows:
List {
OrderItemRow()
OrderItemRow()
}
But as you can see SwiftUI automatically stretches the List to fill all the available space. The effect:
If you know the height of your rows, this can be achieved like this:
List(self.arrayOfAllItemsInOrder(currentOrder)) { item in
OrderItemRow(currentOrder: order, item:item)
}
.environment(\.defaultMinListRowHeight, rowHeight)
.frame(height: self.arrayOfAllItemsInOrder.reduce(0) { i, _ in i + rowHeight })
This will calculate the full size of the list based on rowHeight and limit the frame's height.
Note that if the size of your row goes beyond rowHeight, the entire calculation will be messed up and you will probably be seeing half (or missing entire) cells.
I would suggest a List using a ForEach to show your orders and a nested ForEach to show items in an order. The key is to manage the Data being supplied to each ForEach to the number of items desired and also to construct appropriate Row Views for OrderHeaderRow, OrderItemRow, etc.
struct OrdersView: View {
var body: some View {
List {
Section(header: Text("Current Order")) {
OrderHeaderRow(order: currentOrder)
ForEach(self.arrayOfAllItemsInOrder(currentOrder)) { item in
OrderItemRow(currentOrder: order, item:item)
}
OrderTotalRow(order: order)
ActionButtonsRow(order:order)
}
Section(header: Text("Previous Orders")) {
ForEach(self.arrayOfAllPreviousOrders) { order in
OrderHeaderRow(order: order)
ForEach(self.arrayOfAllItemsInOrder(order)) { item in
OrderItemRow(order: order, item:item)
}
OrderTotalRow(order: order)
ActionButtonsRow(order:order)
}
}
}
}
}

If the cell contains the word "xxx" then do "xxx"

I am working on a spreadsheet and I am trying to create a script, but I don't know how to do this:
I want to write an if statement where if the last row of column B contains the word, let's say "flower", then do something.
Can you please help me?
Thank you in advance.
Here is a working example of how you can use Google Scripts to do an if statement. Paste this into the script editor, then run it. If A1 has the value 1, then it will change B2 to "Yay!", otherwise B2 will be "Really?!"
function myFunction()
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var range = sheet.getRange("A1"); //gets a cell to test the value of
if (range.getValue == 1)
{
sheet.getRange("B2").setValue("Yay!") //sets the value of B2 if true
}
else
{
sheet.getRange("B2").setValue("Really?!") //sets the value of B2 if false
}
}
You can also add in else if if you want to add additional conditions, then whatever manipulation or function you want to do needs to inside the brackets

Accessing a Combobox inside a dataGridView Column?

I'm working on a scheduling program, and inside the dataGridView, we have a few ComboBox Columns that are populated by 3 entries upon creation, but I wanted to be able to add more as the user creates them, but I have no idea how you would access the combobox data. Any help is appreciated!
// this is initialized in a separate part.
/* System::Windows::Forms::DataGridView^ dataGridView;*/
System::Windows::Forms::DataGridViewComboBoxColumn^ newCol =
(gcnew System::Windows::Forms::DataGridViewComboBoxColumn());
dataGridView->Columns->AddRange(gcnew cli::array< System::Windows::Forms::DataGridViewComboBoxColumn^ >(1) {newCol});
// add the choices to the boxes.
newCol->Items->AddRange("User inputted stuff", "More stuff", "Add New...");
Solution
If you have access to the data from the user entry and you know the column index for the DataGridViewComboBoxColumn, you should be able to just do the following wherever needed:
DataGridViewComboBoxColumn^ comboboxColumn = dataGridView->Columns[the_combobox_column_index];
if (comboboxColumn != nullptr)
{
comboboxColumn->Items->Add("the new user entry");
}
Comments Response
how could you change the selected index of that combobox (the one that
the edit was triggered on)? [...] we want it so that when the new item
is added the selected index is set to that new item).
Couple of ways come to mind.
Add a single line within the if-statement of the above code. This will set the default displayed value for each DataGridViewComboBoxCell in the DataGridViewComboBoxColumn.
if (comboboxColumn != nullptr)
{
comboboxColumn->Items->Add("the new user entry");
comboboxColumn->DefaultCellStyle->NullValue = "the new user entry";
}
Pros: Clean, efficient. Previous user-selected values are left intact. The cell's FormattedValue will display the new user value by default if no other selection has been made.
Cons: Doesn't actually set a cell's selected value, so Value will return null on cells not explicitly user-selected.
Actually set the value of certain cells (based on your criteria) to the user-added value.
if (comboboxColumn != nullptr)
{
comboboxColumn->Items->Add("the new user entry");
for (int i = 0; i < dataGridView->Rows->Count; i++)
{
DataGridViewComboBoxCell^ cell = dataGridView->Rows[i]->Cells[the_combobox_column_index];
if ( cell != nullptr /* and your conditions are met */ )
{
cell->Value = "the new user entry";
}
}
}
Pros: The Value of targeted cells is actually set to the new user value.
Cons: Logic deciding which cells should be affected is more complicated.

Get the actual row number of QTableView after drag and drop

At first, the data of the tableview are
apple
pie
banana
After drag and drop(only drag and drop on itself) the item on the tableview, the data of the tableview looks like following
banana
pie
apple
but when I want to iterate the item of the model one by one
codes
for(int i = 0; i != rowCount(); ++i){
if(item(row, Fruit)){
return item(row, Fruit)->data(Qt::DisplayRole).value<QString>();
}
}
it print the data as
apple
pie
banana
expected result
banana
pie
apple
How could I get the “actual” number after drag and drop?
The easiest solution I can think of is create one more column to store the row number of the model, then override the dropEvent, update the row number when the user drop their row.Any easier way to do it?
Edit :
As the example show, the result I want with the codes is "pie, apple, banana".But the actual result is "banana, pie, apple"
The model always operates on the logicalIndex. You need to use the visualIndex of the verticalHeader() for iterating.
for(int i = 0; i < rowCount(); ++i)
{
// i is the logicalIndex
int row = your_table->verticalHeader()->visualIndex(i);
if(item(row, Fruit))
return item(row, Fruit)->data(Qt::DisplayRole).value<QString>();
}

Comparing Substrings to JList Strings

In advance, please forgive me if I do not give adequate background information for my question. Long time reader, first time asker.
I am making a program where one has a database of cars accessed through a tab delimited .txt file (we did something like this recently in my programming class, so I wanted to expand upon it).
Instead of using the terminal window, my format is displaying the Car objects (containing make, model, year, price, etc.) in ArrayList. I'm using JFrame, a JList, and a ListModel since I'm using an array of Car objects.
In my program, I wanted to create a delete method where the user could delete items from the database. Initially they would select the item from the JList and then would click on the delete button. This invokes the delete() method, which is the tab shown below...
void delete()
{
int i = list.getSelectedIndex();
String string = (String)listModel.getElementAt(i);
for(Car c : cars)
{
String year = String.valueOf(c.getYear());
String conditionReport = String.valueOf(c.getConditionReport());
String price = String.valueOf(c.getPrice());
if(c.getMake().indexOf(string) != -1 && c.getModel().indexOf(string) != -1 && year.indexOf(string) != -1 && conditionReport.indexOf(string) != -1 && price.indexOf(string) != -1 && c.getWarranty().indexOf(string) != -1 && c.getComments().indexOf(string) != -1)
{
int choice = JOptionPane.showConfirmDialog(null, "Are you sure you would like to remove the " + cars.get(i).getYear() + " " + cars.get(i).getMake() + " " + cars.get(i).getModel() + "?", "Choose One", JOptionPane.YES_NO_OPTION);
if(choice == JOptionPane.NO_OPTION || choice == JOptionPane.CLOSED_OPTION)
{
return;
} else
{
cars.remove(c);
listModel.removeElementAt(i);
}
}
}
writeFile();
}
I have pinpointed my issue to be inside the if statement. (I printed things before and after to try to find where the program is lying. 'list' is my JList and 'listmodel' is my default list model. Car is an object I created that contains the elements (as seen by the get methods). The elements shown in the listModel are merely Strings that show getMake(), getModel(), and so forth... (Each 'get' item is separated by about 10 spaces.)
What am I doing wrong in the if statement? I figured that the getMake() and getModel() (and so forth) would be substrings of the index selected.
Thank you so much for your assistance! Any input regarding ways I could make further questions more specific and clear would be greatly appreciated!
It seems like you are doing this to find the selected Car in some kind of data structure. You would be better off doing something like programming a custom list model that had access to cars itself. Then you could retrieve the selection more immediately. If cars is an ArrayList that list merely parallels I also don't see why you can't do something to the effect of cars.remove(list.getSelectedIndex());. Or since JList can display any object, override Car's toString to display what the list currently displays and have the list display Cars. Then you can cars.remove((Car)list.getSelectedValue());.
But aside from that, based on your description it sounds like you mean to do the evaluation the other way. It's the list item that should contain all of the Car attributes, rather than all of the Car attributes containing the list item. So something like
if( string.contains(c.getMake()) && string.contains(year) // and so on
(Or with indexOf but since contains merely returns indexOf > -1, using contains makes your code somewhat shorter.)