how to load items in QListWidget with scroll - linux

I am adding icons to a listwidget. It is working good for say a 200 or 300 icons but i may have to add 1000 or above. So i need to add or load the icons in listwidget only when i scroll down. Now i have used a for loop but i need to avoid this
imagefiles = imagedir.entryList(QStringList() << "*.jpg",QDir::Files);
if(imagefiles.isEmpty())
{
empty->raise();
empty->show();
}
else
{
imagelist->repaint();
for(const QString& f:imagefiles)
{
final_row++;
const QString finalimage=imagepath+QString::fromStdString("/") +f;
QFileInfo fi(finalimage);
imagelist->addItem(new QListWidgetItem(QIcon(fi.absoluteFilePath()),fi.fileName()));
}
}

Related

How to set dynamic position of snackbar in jetpack compose?

I have a Scaffold with a NavHost as its content. NavHost host 2 screens. One screen contains the bottomNavigationBar and another screen doesnot.
How can I display create a snack bar that can be used globally which is displayed at the bottom of the screen if no bottomNavigationView is there but adds a bottom padding of height = bottomNavigationHeight if the screen contains bottomNavigationView?
Below is my main content:
#Composable
fun MainScreen() {
val navController = rememberNavController()
val scaffoldState = rememberScaffoldState()
Scaffold(
scaffoldState = scaffoldState
) {
NavHost(navController = navController, "first") {
composable("first") {
FirstScreen()
}
composable("second") {
SecondScreen()
}
}
}
}
My first screen.
// No bottom navigation
#Composable
fun FirstScreen() {
Text("Hello World")
}
My second screen:
// Contains bottom nav
#Composable
fun SecondScreen() {
Scaffold(bottomBar = { MyBottomBar() }) {
}
}
Now, I can use CompositionLocal to send snackBarHostState from scaffold state to all my screens. But, I want first screen to display the snack bar without bottom padding and second screen to display the snack bar with padding for the bottomNavView.
How can I achieve the dynamic position of snackBar??
P.S. This is a simplified version of my issue. I have about 6-7 screen for my MainContent and many screens for the screen with bottom nav.

Using iOS system icons in a NavigationPage with a TabbedPage

I'm using a custom renderer to use iOS system icons in the navigation bar. It works fine, except that if the page is a TabbedPage, only the navigation icons for the default tab's page get their system icons. On other tabs, the system icons don't appear.
My current approach is to override PushViewController. The problem seems to be that when it's called, only the button items for that first tab are available. How can the custom renderer detect when the buttons on the navigation bar are changing? Or is there a better approach?
Current implementation:
/// <summary>
/// Sets system icons on the navigation bar that match the item text.
/// </summary>
class SystemIconNavigationRenderer : NavigationRenderer
{
public override void PushViewController(UIViewController viewController, bool animated)
{
base.PushViewController(viewController, animated);
// If any buttons are customized, replaces the list. Editing individual items doesn't work because UIBarButtonItem.Image is null for a new UIBarButtonItem created from a system item.
var items = viewController.NavigationItem.RightBarButtonItems;
bool changed = false;
var newItems = new UIBarButtonItem[items.Length];
for (int i = 0; i < items.Length; ++i) {
var item = items[i];
UIBarButtonSystemItem systemItem = (UIBarButtonSystemItem)(-1);
switch (item.Title) {
case nameof(UIBarButtonSystemItem.Add): systemItem = UIBarButtonSystemItem.Add; break;
// More icons...
}
if (systemItem >= 0) {
newItems[i] = new UIBarButtonItem(systemItem) { Action = item.Action, Target = item.Target };
changed = true;
} else
newItems[i] = item;
}
if (changed) viewController.NavigationItem.RightBarButtonItems = newItems;
}
}

Get Visible Text from RichTextBlock

In a UWP app, I am using a RichTextBlock that gets populated with some content. It has word wrapping enabled and has a max lines set so that regardless of the length of its content, it will only show a certain number of lines of rich text.
I'd like to know if there is a way to figure out what is the visible text?
So if I have:
<RichTextBlock TextWrapping="Wrap" MaxLines="2">
<RichTextBlock.Blocks>
<Paragraph>
<Paragraph.Inlines>
A bunch of runs go in here with text that are several lines
</Paragraph.Inlines>
</Paragraph>
</RichTextBlock.Blocks>
</RichTextBlock>
I'd like to know how much of the text is actually visible.
I'm trying to detect cases where the text is longer than a set number of lines and append a "... Read More" at the end of the last line (replacing the last 13 chars with "... Read More")
So I wrote some code to get the behavior that I want, but unfortunately this is rather slow and inefficient. So if you're using it in an app that is primarily to show a lot of text that needs to be truncated (like a ListView with a lot of text items) then this would slow down your app perf. I still would like to know if there is a better way to do this.
Here's my code (which only handles Run and Hyperlink inlines so you'll have to modify to handle other types that you need):
private static void TrimText_Slow(RichTextBlock rtb)
{
var paragraph = rtb?.Blocks?.FirstOrDefault() as Paragraph;
if (paragraph == null) { return; }
// Ensure RichTextBlock has passed a measure step so that its HasOverflowContent is updated.
rtb.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
if (rtb.HasOverflowContent == false) { return; }
// Start from end and remove all inlines that are not visible
Inline lastInline = null;
var idx = paragraph.Inlines.Count - 1;
while (idx >= 0 && rtb.HasOverflowContent)
{
lastInline = paragraph.Inlines[idx];
paragraph.Inlines.Remove(lastInline);
idx--;
// Ensure RichTextBlock has passed a measure step now with an inline removed, so that its HasOverflowContent is updated.
rtb.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
}
// The last inline could be partially visible. The easiest thing to do here is to always
// add back the last inline and then remove characters from it until everything is in view.
if (lastInline != null)
{
paragraph.Inlines.Add(lastInline);
}
// Make room to insert "... Read More"
DeleteCharactersFromEnd(paragraph.Inlines, 13);
// Insert "... Continue Reading"
paragraph.Inlines.Add(new Run { Text = "... " });
paragraph.Inlines.Add(new Run { Text = "Read More", Foreground = new SolidColorBrush(Colors.Blue) });
// Ensure RichTextBlock has passed a measure step now with the new inlines added, so that its HasOverflowContent is updated.
rtb.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
// Keep deleting chars until "... Continue Reading" comes into view
idx = paragraph.Inlines.Count - 3; // skip the last 2 inlines since they are "..." and "Read More"
while (idx >= 0 && rtb.HasOverflowContent)
{
Run run;
if (paragraph.Inlines[idx] is Hyperlink)
{
run = ((Hyperlink)paragraph.Inlines[idx]).Inlines.FirstOrDefault() as Run;
}
else
{
run = paragraph.Inlines[idx] as Run;
}
if (string.IsNullOrEmpty(run?.Text))
{
paragraph.Inlines.Remove(run);
idx--;
}
else
{
run.Text = run.Text.Substring(0, run.Text.Length - 1);
}
// Ensure RichTextBlock has passed a measure step now with the new inline content updated, so that its HasOverflowContent is updated.
rtb.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
}
}
private static void DeleteCharactersFromEnd(InlineCollection inlines, int numCharsToDelete)
{
if (inlines == null || inlines.Count < 1 || numCharsToDelete < 1) { return; }
var idx = inlines.Count - 1;
while (numCharsToDelete > 0)
{
Run run;
if (inlines[idx] is Hyperlink)
{
run = ((Hyperlink)inlines[idx]).Inlines.FirstOrDefault() as Run;
}
else
{
run = inlines[idx] as Run;
}
if (run == null)
{
inlines.Remove(inlines[idx]);
idx--;
}
else
{
var textLength = run.Text.Length;
if (textLength <= numCharsToDelete)
{
numCharsToDelete -= textLength;
inlines.Remove(inlines[idx]);
idx--;
}
else
{
run.Text = run.Text.Substring(0, textLength - numCharsToDelete);
numCharsToDelete = 0;
}
}
}
}

Detect scrolling event on listview with winjs

I need to load more items as soon as the user scroll to the end of my list view.
I tried to use the microsoft sample : http://code.msdn.microsoft.com/windowsapps/ListView-loading-behaviors-718a4673/view/SourceCode (scenario 2) but it seams that list view have not the same behavior in windows phone 8.1.
When I run the sample I can see that only viewable contents are loaded (eg 5items of 50).
But for windows phone it does load all items.
I use this code :
listView.winControl.itemTemplate = this.incrementalTemplate;
incrementalTemplate: function (itemPromise, recycledElement) {
if (!recycledElement) {
recycledElement = document.createElement('div');
}
var renderComplete = itemPromise.then(function (item) {
console.log(item.index);
itemTemplate.winControl.render(item.data, recycledElement);
return item.ready;
}).done(function (item) {
console.log("clp"+item.index);
});
return { element: recycledElement, renderComplete: renderComplete };
},
Items are loaded asynchronusly. I can see in my console that it print 50 times the index and 50times the clp+index. Even if my list just show 5 items at a time.
Also it seems that my listview never fired the loading state event
listView.addEventListener("loadingstatechanged", function (args) {
//never fired
}, false);
The listview is in a hub, the solution was to add an onscroll event on the win pivot item:
document.querySelector(".win-pivot-item-content").onscroll = function () {
if (self.scrollAtBottom(this) === true) {
//load more
}
};
scrollAtBottom : function(element){
return element.scrollHeight - element.scrollTop === element.clientHeight
},
If you want to subscribe to event when the ListView was scrolled, you can take ListView's Scrollviewer and subscribe to ViewChanged event. The only problem is that I do not know how it would look like in winjs, in C# it can look like that:
// method to pull out a ScrollViewer
public static ScrollViewer GetScrollViewer(DependencyObject depObj)
{
if (depObj is ScrollViewer) return depObj as ScrollViewer;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
var child = VisualTreeHelper.GetChild(depObj, i);
var result = GetScrollViewer(child);
if (result != null) return result;
}
return null;
}
// subscription:
GetScrollViewer(yourListView).ViewChanged += yourEvent_ViewChanged;
Maybe it will help.
The comment voted here as solution does not work just like that out the box, however I found a solution to this problem starting from that.
See my first answer on the issue I opened at https://github.com/winjs/winjs/issues/690#issuecomment-61637832 (includes code snippet)

Why is UILabel not updating?

I have created a view that shows lost connection messages to users which pops over the current view. I want to update the view periodically based on connection status changes.
I can properly get the view and change the text of a label (verified with WriteLines), but nothing changes on the actual display. I even tried removing the view and readding it and calling SetNeedsDisplay, but nothing seems to help.
I have a global variable called OverView:
public static UIView OverView;
I create the label subview, add it to the overview and pop the overview in front of the current view:
UILabel labelTitle = new UILabel();
labelTitle.Text = title;
UIView labelTitleView = (UIView) labelTitle;
labelTitleView.Tag = 5000;
OverView.AddSubview(labelTitleView);
curView.InsertSubviewAbove(OverView, curView);
curView.BringSubviewToFront(OverView);
And then at a later time, I try to modify it like this from another function:
if ((OverView != null) && (OverView.Subviews != null))
{
for (int i = 0; i < OverView.Subviews.Length; i++)
{
WriteToConsole("Type: " + OverView.Subviews[i].GetType());
if (OverView.Subviews[i] is UILabel)
{
WriteToConsole("Found Label with Tag: " + ((UILabel)(OverView.Subviews[i])).Tag + " Text: " + ((UILabel)(OverView.Subviews[i])).Text);
if (((UILabel)(OverView.Subviews[i])).Tag == 5000)
{
WriteToConsole("Setting subview Title to: " + lostConnectionTitle);
lock (overViewLocker)
{
appReference.InvokeOnMainThread(delegate
{
UILabel tempLabel = ((UILabel)(OverView.Subviews[i]));
tempLabel.Text = lostConnectionTitle;
OverView.Subviews[i].RemoveFromSuperview();
OverView.AddSubview(tempLabel);
OverView.BringSubviewToFront(tempLabel);
OverView.SetNeedsLayout();
OverView.SetNeedsDisplay();
WriteToConsole("SetNeedsDisplay");
});
}
}
}
}
}
Have you tried to use delegate methods on your label, and change their value when events occur ?
For example, if your event is clicking on a button, you should have something like that:
yourLabel.Text = "Init";
buttonExample.TouchUpInside += (sender, e) => {
yourLabel.Text = "I touched my button";
};
When your View loads, you'll see "Init" and your button and once you click on it, the label text changed.
Xamarin has some explanation about events and delegate methods here.
I hope that helped.

Resources