Flutter - Cannot modify List<Widget> - list

I have a fixed-length List that is used in the "build" function. I want to replace one element in that List with another. Both elements in the List are Containers. I replace the element in the List and do a setState(). The build function uses the List in the body of the Scaffold. I get no error, however when the rebuild is done, nothing has changed.
To my knowledge this is not breaking any rules and as far as I know should cause no problems.
While I could code around the issue, I think that with something as fundamental as this, I need to find the reason for it.
Any ideas as to why this is happening?
Code added below:
Below is the code that DOES NOT work
if (_lwDisplay[iNdxDisplay] == null) /*INITIAL DISPLAY */ {
_lwDisplay[iNdxDisplay] = wContainer;
} else {
setState(() {
_tfDataHasChanged = true;
_lwDisplay[iNdxDisplay] = wContainer;
});
}
Below is the code that DOES work
if (_lwDisplay[iNdxDisplay] == null) /*INITIAL DISPLAY */ {
_lwDisplay[iNdxDisplay] = wContainer;
} else {
_tfDataHasChanged = _fnHasDataChanged() /* FOR FAB */;
List<Widget> lwDisplay2 = List(_lwDisplay.length);
for (int iNdx = 0; iNdx < lwDisplay2.length; iNdx++) {
if (iNdx != iNdxDisplay) {
lwDisplay2[iNdx] = _lwDisplay[iNdx];
}
}
lwDisplay2[iNdxDisplay] = wContainer;
_lwDisplay = lwDisplay2;
setState(() {});
}

Without seeing the entirety of code, and according to this SO question,
Move the instantiation of the list of widgets to the build method of your main widget.
I.E.
class MainWidgetState extends State<MainWidget> {
List<YOUR_WIDGET> _lwDisplay = new List();
Widget build(BuildContext context) {
//Create your list
}
}
Also, add a key to each item in your widget (if you haven't done so already).

Related

Create a new object from pointer reference C++

So, I've this code below:
foreach (QLineSeries* series, lineSeriesMap.values())
{
// ...
}
And I will modify series objects in this loop and I don't want to modify the original one, but create a new edited one. I'm extremely new to C++ and Qt so, I want something as the Java code below:
QLineSeries editedSeries = new QLineSeries(series);
I'm deleting elements, editing and re-ordering them from series by the way. But, as I said I need them both.
EDIT:
I've tried your answers but best way I believe is putting the code. This is a project made by some co-worker who changed jobs so its not my code, as i said I dont know C++.
chartwidget.h
void fillAreaSeries();
//...
QHash<QString,QLineSeries*> lineSeriesEntersMap;
QHash<QString,QLineSeries*> lineSeriesExitsMap;
chartwidget.cpp
void ChartWidget::fillAreaSeries() {
foreach (QLineSeries* seriesEnter, lineSeriesEntersMap.values())
{
if (lineSeriesExitsMap.contains(seriesEnter->name())) {
QLineSeries* seriesExit = lineSeriesExitsMap.value(seriesEnter->name());
if (!((seriesEnter->points().size() == 1) && (seriesExit->points().size() == 1))) {
for(int i = seriesEnter->points().size() - 1; i > 0; i--)
{
if (seriesEnter->points().at(i - 1).y() > seriesEnter->points().at(i).y())
{
seriesEnter->removePoints(i, 1);
}
}
for (int i = seriesExit->points().size() - 1; i > 0; i--)
{
if (seriesExit->points().at(i - 1).y() < seriesExit->points().at(i).y())
{
seriesExit->removePoints(i-1, 1);
}
}
QVector<QPointF> editPoints = seriesExit->pointsVector();
std::sort(editPoints.begin(),editPoints.end(), [] (const QPointF & p1, const QPointF & p2)
{
return p1.y() < p2.y();
});
seriesExit->replace(editPoints);
qDebug() << "__Swap:__";
qDebug() << seriesEnter->points().at(0).y();
qDebug() << seriesExit->points().at(0).y();
qDebug() << seriesEnter->points().at(1).y();
qDebug() << seriesExit->points().at(1).y();
QAreaSeries* series = new QAreaSeries(seriesEnter, seriesExit);
series->setName(seriesEnter->name());
series->setOpacity(0.50);
series->setPen(Qt::NoPen);
series->setPointLabelsFormat(seriesEnter->name().split("-").at(0));
areaSeriesMap.insert(series->name(), series);
}
}
}
}
Edit 3:
So, QLineSeries contains QPointF list. I've the code below:
foreach (QLineSeries* seriesEnter, lineSeriesEntersMap.values())
{
QLineSeries* entersToBeEdited = new QLineSeries(chart);
entersToBeEdited->setName(seriesEnter->name());
entersToBeEdited->points().append(seriesEnter->points());
//...
append doesnt work and returns 0 points. But I can set a name. I also tried appending by looping through items and adding it by
entersToBeEdited->points().push_back(seriesEnter->points().at(i));
and still nothing. I also tried << and += but no luck.
Looking at the class definition of QLineSeries, I don't see any simple way to copy your instance in order to duplicate it.
Thus you will have first to create a new instance :
QLineSeries editedSeries;
and manually copy the content of your original series in it.
editedSeries.append(originalSeries.points());
As you cannot modify the data once it is in the QLineSeries object, I would recommend to subclass QLineSeries or modify the QList<QPointF> obtained via originalSeries.points() before adding it to your new chart.
QLineSeries is not copyable, so you can't do what you want by modifying a copy. You will need to create a new QLineSeries from scratch.

list does not scroll while extending container in lwuit

List does not scroll while adding images in container. I have a list that extends container. I have used two containers for setting image field(left) and text filed(right). while I am adding text filed container list scrolls properly but while adding images in left field it did not scroll please help me . Thank you for your help.
//List declaration
orgNames = new List(tempName);
WidgetRenderer listCheckBoxRenderer = new WidgetRenderer();
orgNames.setListCellRenderer(listCheckBoxRenderer);
orgNames.setFixedSelection(List.FIXED_TRAIL);
organizationDetailsForm.addComponent(orgNames);
OrganizationNameListener orgNameList = new OrganizationNameListener();
orgNames.addActionListener(orgNameList);
//List renderer class
class WidgetRenderer extends Container implements ListCellRenderer {
private Image[] images;
private Button orgImgButton;
private Image orgImg;
private Container contImage, contDet;
private Label orgNameLabel, locationLabel, ratingLabel;
public WidgetRenderer() {
super();
try {
setLayout(new BorderLayout());
contDet = new Container(new BoxLayout(BoxLayout.Y_AXIS));
contImage = new Container();
contDet.setScrollableY(true);
contImage.setScrollable(true);
contDet.setScrollable(true);
contImage.setScrollable(true);
contDet.setSmoothScrolling(true);
contImage.setSmoothScrolling(true);
setScrollable(true);
setScrollableY(true);
orgImgButton = new Button();
orgNameLabel = new Label();
locationLabel = new Label();
Style orgStyle = new Style();
Style locStyle = new Style();
Font font = Font.createSystemFont(Font.FACE_MONOSPACE,
Font.STYLE_BOLD, Font.SIZE_MEDIUM);
orgStyle.setFont(font);
orgNameLabel.setSelectedStyle(orgStyle);
orgNameLabel.setPressedStyle(orgStyle);
orgNameLabel.setUnselectedStyle(orgStyle);
Font font1 = Font.createSystemFont(Font.FACE_MONOSPACE,
Font.STYLE_PLAIN, Font.SIZE_SMALL);
locStyle.setFont(font1);
locationLabel.setSelectedStyle(locStyle);
locationLabel.setPressedStyle(locStyle);
locationLabel.setUnselectedStyle(locStyle);
ratingLabel = new Label();
contImage.addComponent(orgImgButton);
contDet.addComponent(orgNameLabel);
contDet.addComponent(locationLabel);
addComponent(BorderLayout.WEST, contImage);
addComponent(BorderLayout.CENTER, contDet);
} catch (Exception ex) {
System.out.println("ex" + ex.getMessage());
}
}
public Component getListCellRendererComponent(List list, Object value,
int index, boolean isSelected) {
// System.out.println("adding names & loc");
setFocus(isSelected);
for (int i = 0; i < list.size(); i++) {
if (index == i) {
orgNameLabel.setText(tempName[i]);
locationLabel.setText(districtDesc[i] + "," + townDesc[i]);
orgImgButton.setIcon(DefaultLayout.CreateScaledImage(loadImage(thumbnailURL), DefaultLayout.screenWidth()*10/100, DefaultLayout.screenHeight()*9/100));
}
}
if (isSelected) {
getStyle().setBgColor(0x00BFFF);
getStyle().setBgTransparency(100);
} else {
getStyle().setBgTransparency(30);
}
return this;
}
You are invoking scaled() which is a VERY slow and expensive operation within a renderer which must be REALLY fast. Not a good idea. Not sure if that answers your issue but I suggest investigating whether the TRAIL flag is the cause of your issue.

Copying a (rtf) table into the clipboard via QT (or: Writing a QTextDocument into clipboard)

I need my QT application to create a table and copy this table into the clipboard, so that it can be pasted as table into libreoffice Writer or MS Word later.
My first approach was to create html code for the table and insert it into the clipboard with
QClipboard *clipboard = QApplication::clipboard();
QMimeData *mimeData = new QMimeData();
mimeData->setData("text/html", html.toUtf8());
clipboard->setMimeData(mimeData, QClipboard::Clipboard);
This approach didn't work. When pasting, the table cells where just appended to each other and inserted without formatting.
My second approach using RTF:
QTextDocument rtfDocument;
rtfDocument.setHtml(html);
But I found no way to copy this QTextDocument into the clipboard. Is there any?
If I could get the RTF code out of the QTextDocument, I could use a way like
QClipboard *clipboard = QApplication::clipboard();
QMimeData *mimeData = new QMimeData();
mimeData->setData("text/rtf", rtfDocument.getCode());
clipboard->setMimeData(mimeData, QClipboard::Clipboard);
But I also didn't find a function returning the rtf code.
edit:
With the last code box above I have a working way to copy rtf code into the clipboard. So any solution that can create RTF code representing a table would solve my problem.
I'm not sure what the source of your data is, but here is code we used to subclass the normal QTableView to make it copy-able. Some of the code has been cut out, but you can get the basic idea. RTF/HTML is overkill--all the spreadsheets accept good ol' CSV.
Of course, this answer won't help at all if you require formatting. I wasn't clear from your question if that was a requirement or not.
// Escapes a string according to RFC-4180 specification.
static QString csvEscape(const QString &value) {
if (value.contains(QRegExp(QLatin1String("[\"\\n\\r,]")))) {
QString escaped(value);
escaped.replace(QLatin1String("\""), QLatin1String("\"\""));
return QString::fromLatin1("\"%1\"").arg(escaped);
} else {
return value;
}
}
void ClipboardAwareTableView::Copy() const {
QModelIndexList indexes = selectedIndexes();
Q_ASSERT(!indexes.isEmpty());
if(indexes.isEmpty()) {
return;
}
// The default sort is by rows then columns. This is what we want.
qSort(indexes);
// Remember the mapping between model columns and visible columns. This is
// local instead of an instance member because it would need to be invalidated
// any time a column is added, removed, or moved. The minor performance hit
// is worth the simplicity.
QHash<int, int> map_cache;
// Before we start exporting text, we have to know the index of the left-
// most column in our selection range so we can add the appropriate number
// of column separators.
int minimum_column = GetViewColumnIndex(indexes.first().column(), &map_cache);
for (int i = 1; i < indexes.size(); ++i) {
minimum_column =
qMin(minimum_column,
GetViewColumnIndex(indexes.at(i).column(), &map_cache));
}
// Keep track of the previous index so that we know if we need a new line and
// how many column separators to insert. We start with an invalid index.
QModelIndex previous;
QString text;
for (int i = 0; i < indexes.size(); ++i) {
QModelIndex current = indexes.at(i);
// Do we need to add a new line character?
if (previous.isValid() && current.row() != previous.row()) {
text.append(QLatin1String("\n"));
}
// Are we on a new line?
if (!previous.isValid() || current.row() != previous.row()) {
// Add enough separators to get from the minimum to the current column.
text.append(QString::fromLatin1(",")
.repeated(GetViewColumnIndex(current.column(), &map_cache) -
minimum_column));
} else {
// Add enough separators to get from the previous to the current column.
text.append(QString::fromLatin1(",")
.repeated(GetViewColumnIndex(current.column(), &map_cache) -
GetViewColumnIndex(previous.column(), &map_cache)));
}
// Append the text. If the column delegate is a QStyledItemDelegate, we use
// the display text.
QStyledItemDelegate *delegate =
qobject_cast<QStyledItemDelegate*>(
itemDelegateForColumn(current.column()));
if (delegate) {
text.append(csvEscape(delegate->displayText(current.data(), QLocale())));
} else {
text.append(csvEscape(current.data().toString()));
}
previous = current;
}
qApp->clipboard()->setText(text);
}
int ClipboardAwareTableView::GetViewColumnIndex(
int model_column_index,
QHash<int, int> *cached_mappings) const {
if (cached_mappings->contains(model_column_index)) {
return cached_mappings->value(model_column_index);
}
int view_index = 0;
for (int i = 0; i < model()->columnCount(); ++i) {
if (model_column_index == i) {
cached_mappings->insert(model_column_index, view_index);
return view_index;
} else if (!isColumnHidden(i)) {
++view_index;
}
}
throw std::invalid_argument("model_column_index was out of range.");
}
void ClipboardAwareTableView::keyPressEvent(QKeyEvent *event) {
if (event->matches(QKeySequence::Copy) && !selectedIndexes().isEmpty()) {
Copy();
event->accept();
return; // The base class implementation will overwrite the clipboard.
}
event->ignore();
QTableView::keyPressEvent(event);
}
You could try using QTextDocument::toHtml() and set the mime type to text/html
I wrote in gedit 1[tab space]2[tab space]3\n4[tab space]5[tab space]6 and copied it to spreadsheet and it worked. So, I think if you use "\t" for separating cells in rows and "\n" for separating rows, it will work.

In QListWidget how do i check if QListWidgetItem already exists based on its Data member

im setting item's in QListWidget and in each QListWidgetItem im setting id like this:
newItem->setData(Qt::DisplayRole,ID);
now each time before im adding the itemi wish to check if already there is item with the same data in the list .
how can i do that ... i don't think the findItems will help me here
Let me assume that type of ID is int (cause you didn't specify it).
bool found = false;
for (int i = 0; i < list->count(); ++i) {
if (list->item(i)->data(Qt::DisplayRole).toInt() == ID_to_match) {
found = true;
break;
}
}
if (!found) {
do_something_here();
}

Sitecore Workflow and Pipelines

I'm trying to implement a basic Javascript confirmation box on a workflow command (e.g. "are you sure you want to edit this?"). Depending on whether a users clicks yes or no, I want to move to a different state in the workflow. Here is the code I currently have (some logic is taken out):
[Serializable]
public class ConfirmAction
{
public void Process(WorkflowPipelineArgs args)
{
Item currentItem = args.DataItem;
ClientPipelineArgs clientArgs = new ClientPipelineArgs();
Sitecore.Context.ClientPage.Start(this, "DialogProcessor", clientArgs);
}
protected void DialogProcessor(ClientPipelineArgs args)
{
if (args.IsPostBack)
{
if (args.Result != "yes")
{
args.AbortPipeline();
return;
}
}
else
{
Sitecore.Context.ClientPage.ClientResponse.Confirm("Are you sure you want to edit this?");
args.WaitForPostBack();
}
}
}
I'm new to the Pipeline model, especially in relation to Sitecore, so I'm somewhat grasping at straws. The problem that I'm having, I believe, is that I don't have a way of getting the result back to the Workflow Pipeline, from the ClientResponse pipeline, to tell it what to do.
Thank you.
EDIT:
Using Yan's information, I eventually came up with the following solution:
public void Process(WorkflowPipelineArgs args)
{
Item currentItem = args.DataItem;
ClientPipelineArgs clientArgs = new ClientPipelineArgs();
clientArgs.Parameters.Add("itemID", currentItem.ID.ToString());
clientArgs.Parameters.Add("stateID", currentItem.Fields["__Workflow state"].Value);
Sitecore.Context.ClientPage.Start(this, "DialogProcessor", clientArgs);
}
protected void DialogProcessor(ClientPipelineArgs args)
{
if (args.IsPostBack)
{
if (args.Result != "yes")
{
Item currentItem = Sitecore.Configuration.Factory.GetDatabase("master").GetItem(args.Parameters["itemID"]);
currentItem.Editing.BeginEdit();
currentItem.Fields["__Workflow state"].Value = args.Parameters["stateID"];
currentItem.Editing.EndEdit();
return;
}
SheerResponse.Eval("window.location.reload();");
}
else
{
Sitecore.Context.ClientPage.ClientResponse.YesNoCancel("Are you sure you want to edit this?", "200", "200");
args.WaitForPostBack();
}
}
Well, I think this is where you can take advantage from ClientPipelineArgs. Let's say you add the current item ID to the parameters to pass:
public void Process(WorkflowPipelineArgs args)
{
Item currentItem = args.DataItem;
ClientPipelineArgs clientArgs = new ClientPipelineArgs();
clientArgs.Parameters.Add("id", currentItem.ID.ToString());
Sitecore.Context.ClientPage.Start(this, "DialogProcessor", clientArgs);
}
and later on when you get positive result you get it back and move to the target workflow state (explained in comments):
protected void DialogProcessor(ClientPipelineArgs args)
{
if (args.IsPostBack)
{
if (args.Result == "yes")
{
// 1. take item ID from args.Parameters["id"];
// 2. get item by this ID
// 3. move item to target workflow state
}
}
else
{
Sitecore.Context.ClientPage.ClientResponse.Confirm("Are you sure you want to edit this?");
args.WaitForPostBack();
}
}
This might require some minor changes (I didn't run it myself before posting), but hope you get the idea.