Results 1 to 5 of 5

Thread: QQuickView redraw: setSource() 2nd time leads to Qt-Assert

  1. #1
    Join Date
    Jan 2012
    Location
    Dortmund, Germany
    Posts
    159
    Thanks
    69
    Thanked 10 Times in 8 Posts
    Qt products
    Qt4
    Platforms
    Windows Android

    Default QQuickView redraw: setSource() 2nd time leads to Qt-Assert

    Hi,
    I have a QuickView interface where the user can edit data.

    A reset button (inside the interface) sets the underlying data (an interface object that is set as a context property) back to model data by calling a slot in that very interface object. Unfortunately, the qml content is not being visibly updated.

    I'd be happy with just rebuilding the QML content from scratch by setting the QQuickview's source anew after resetting my data, like here:

    Qt Code:
    1. void ControllerClass::redrawIncEditView()
    2. {
    3. Q_ASSERT(m_quickView);
    4. auto url = m_quickView->source();
    5. // m_quickView->hide();
    6. m_quickView->setSource(url); //<<<<< HERE we have the assert you see below
    7. // m_quickView->show();
    8. }
    To copy to clipboard, switch view to plain text mode 

    But calling this leads to a crash in Qt:
    ASSERT: "context() && engine()" in file qml\qqmlboundsignal.cpp, line 183
    I have no idea why the crash occurs. Ive seen very similar / same error messages on Google, but in quite different contexts, as far as I can see.

    I've also tried calling the following methods of QQuickView, but they don't show any effect (probably they just cover the graphical aspects):
    Qt Code:
    1. m_quickView->update();
    2. m_quickView->requestUpdate();
    3. m_quickView->renderTarget();
    To copy to clipboard, switch view to plain text mode 

    Interesting update:

    The above approach works when started by a single shot timer. Therefore I have to subclass QQuickView, adding a "redraw"-method that takes no argument (to make it usable with QTimer::singleShot):
    Qt Code:
    1. class MyQQuickView: public QQuickView {
    2. Q_OBJECT
    3. public slots:
    4. void redraw() { this->setSource(this->source()); }
    5. };
    To copy to clipboard, switch view to plain text mode 
    and call that in this way:
    Qt Code:
    1. void ControllerClass::redrawIncEditView()
    2. {
    3. Q_ASSERT(m_quickView);
    4. QTimer::singleShot(1,m_quickView,SLOT(redraw()));
    5. }
    To copy to clipboard, switch view to plain text mode 

    Any idea about what is behind the crash? Is it a threading problem?
    Are there better / more elegant ways to force a QML redraw?
    Is that hack somewhat safe in the first place? I can use it with 1 ms here - but could this be different on a phone?
    Last edited by sedi; 6th August 2016 at 01:24.

  2. #2
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: QQuickView redraw: setSource() 2nd time leads to Qt-Assert

    Quote Originally Posted by sedi View Post
    A reset button (inside the interface) sets the underlying data (an interface object that is set as a context property) back to model data by calling a slot in that very interface object. Unfortunately, the qml content is not being visibly updated.
    The editing probably replaced the property binding you originally had.

    Can you show the QML code?

    Quote Originally Posted by sedi View Post
    But calling this leads to a crash in Qt:
    Very strange.
    How about
    Qt Code:
    1. const QUrl source = view->source();
    2. view->engine()->clearComponentCache();
    3. view->setSource(source);
    To copy to clipboard, switch view to plain text mode 

    Quote Originally Posted by sedi View Post
    Any idea about what is behind the crash? Is it a threading problem?
    Unlikely. The trigger comes from within the main UI thread, the view is on that thread.

    Quote Originally Posted by sedi View Post
    Are there better / more elegant ways to force a QML redraw?
    You don't need to force redraw, you want the displayed data to be updated.
    Just forcing redraw of the old data doesn't get you anywhere.

    Quote Originally Posted by sedi View Post
    Is that hack somewhat safe in the first place? I can use it with 1 ms here - but could this be different on a phone?
    No, that should be ok but you might want to look into solving the actual problem

    Cheers,
    _

  3. The following user says thank you to anda_skoa for this useful post:

    sedi (20th August 2016)

  4. #3
    Join Date
    Jan 2012
    Location
    Dortmund, Germany
    Posts
    159
    Thanks
    69
    Thanked 10 Times in 8 Posts
    Qt products
    Qt4
    Platforms
    Windows Android

    Default Re: QQuickView redraw: setSource() 2nd time leads to Qt-Assert

    Hi and thanks for your time and attention,

    Qt Code:
    1. view->engine()->clearComponentCache();
    To copy to clipboard, switch view to plain text mode 
    is an interesting idea! I had not tried that before, but unfortunately it doesn't help, too (same crash).

    As to the basic structure of what I am doing here: I have different kinds of incidents in my model which all derive from an "Incident" base class. For interaction with qml I cache this in different interfaces which also derive from one "IncEditInterface", which covers the "Incident" base stuff.

    On qml side I use a IncEdit.qml which allows the editing of the base class properties of the interface (most of them invisible by default, opening on demand). The additional properties of the derived classes are covered by a Loader that - depending on the actual class - sideloads additional interface elements by taking the source of a class-specific qml file.

    Structure:
    model:
    incident (base)
    --> incidentA (derived)
    --> incidentB (derived)
    --> incidentC (derived)

    interface:
    incEditInterface (base)
    --> incEditInterfaceA(derived)
    --> incEditInterfaceB (derived)
    --> incEditInterfaceC (derived)

    QML
    incEdit.qml
    {
    [base class stuff]
    Loader.source = "interfaceA.qml"
    [additional base class stuff]
    }

    The actual qml code is this one (destilled for readability):
    Qt Code:
    1. import QtQuick 2.5
    2. import QtQuick.Controls 1.4
    3. import QtQuick.Dialogs 1.2
    4. [imports]
    5.  
    6. Flickable {
    7. id: incEditFlickable
    8. [Layout/Size stuff]
    9. Item {
    10. id: incEditBaseItem
    11. [Layout/Size stuff]
    12. property string pupilDisplayNameComposition: IncEditInterface.pupilFullName + " ("+ priv.nick + priv.gender + ")"
    13. QtObject {
    14. id: priv
    15. property string nick: IncEditInterface.pupilNickName ? IncEditInterface.pupilNickName + ", " : ""
    16. property string gender: IncEditInterface.pupilGender === Enums.MALE ? "m" : IncEditInterface.pupilGender === Enums.FEMALE ? "w" : "?"
    17.  
    18. }
    19. // optionally overlaid dialog items ------------------------------------------------------------------------------------------------------------
    20. Calendar {
    21. z: 500
    22. visible:false
    23. id: datePickerBookedFor
    24. [Layout/Size stuff]
    25. onClicked: {
    26. datePickerBookedFor.visible = false
    27. dateButton.text = Qt.formatDate(date, "ddd dd.MM.yy")
    28. IncEditInterface.bookedForDate = date
    29. dateButton.shrinkToFitFromPixelSize(pupilNameSmall.font.pixelSize)
    30. }
    31. }
    32.  
    33. // incEditButtons -----------------------------------------------------------------------
    34. RowLayout {
    35. id: incEditButtonRow
    36. [Layout/Size stuff]
    37. CustomIconPushButton {
    38. id: okButton
    39. [...]
    40. }
    41. CustomIconPushButton {
    42. id: adoptButton
    43. [...]
    44. }
    45. CustomIconPushButton {
    46. id: resetButton
    47. [Layout/Size stuff]
    48. text: "Reset"
    49. onPushButtonClicked: {
    50. IncEditInterface.resetEntries()
    51. }
    52. }
    53. CustomIconPushButton {
    54. id: deleteButton
    55. [...]
    56. }
    57.  
    58. }
    59.  
    60. // small version of incEdit header --------------------------------------------------------------------------------------------------------------
    61. Rectangle {
    62. id: smallTopItem
    63. [Layout/Size stuff]
    64. visible: true
    65. Rectangle {
    66. id: pupilNameSmallRect
    67. [Layout/Size stuff]
    68. Text {
    69. id: pupilNameSmall
    70. [Layout/Size stuff]
    71. text: incEditBaseItem.pupilDisplayNameComposition
    72. }
    73. }
    74. CustomIconPushButton {
    75. id: showHideTitle1
    76. visible: true
    77. [Layout/Size stuff]
    78. text: "s"
    79. onPushButtonClicked: {
    80. smallTopItem.visible = false;
    81. largeTopItem.visible = true;
    82. }
    83. }
    84. }
    85. // large version of incEdit header --------------------------------------------------------------------------------------------------------------
    86. Rectangle {
    87. id: largeTopItem
    88. [Layout/Size stuff]
    89. visible: false
    90. Rectangle {
    91. id: pupilNameLargeRect
    92. color: "transparent"
    93. [Layout/Size stuff]
    94. Image {
    95. id: pupilPicture
    96. [Layout/Size stuff]
    97. source: IncEditInterface.pupilCustomPictureFileName === "" ? "" : IncEditInterface.paths.customPicturePath+IncEditInterface.pupilCustomPictureFileName
    98. fillMode: Image.PreserveAspectFit
    99. }
    100. Text {
    101. id: pupilNameLarge
    102. [Layout/Size stuff]
    103. text: incEditBaseItem.pupilDisplayNameComposition
    104. }
    105. SetCombo {
    106. Component.onCompleted: {
    107. groupCombo.currentIndex = groupCombo.find(IncEditInterface.groupName)
    108. }
    109.  
    110. id: groupCombo
    111. enabled: !datePickerBookedFor.visible
    112. [Layout/Size stuff]
    113. model: IncEditInterface.groupNames
    114. textRole: "text"
    115. onCurrentTextChanged: {
    116. IncEditInterface.groupName = groupCombo.currentText
    117. }
    118. }
    119. CustomIconPushButton {
    120. id: dateButton
    121. [Layout/Size stuff]
    122. text: Qt.formatDate(IncEditInterface.bookedForDate, "ddd dd.MM.yy")
    123. onPushButtonClicked: {
    124. datePickerBookedFor.visible = true
    125. }
    126. }
    127. CustomIconPushButton {
    128. id: showHideTitle2
    129. [Layout/Size stuff]
    130. text: "h"
    131. onPushButtonClicked: {
    132. smallTopItem.visible = true;
    133. largeTopItem.visible = false;
    134. }
    135. }
    136. } //pupilNameLargeRect
    137. } //largeTopItem
    138. Loader {
    139. id: incEditLoader
    140. [Layout/Size stuff]
    141. source: IncEditInterface.loaderSourceUrl
    142. }
    143. SetTextAreaInput {
    144. id: additionalInfoTextInput
    145. [Layout/Size stuff]
    146. title: "Bemerkungen:"
    147. text: IncEditInterface.additionalInfo
    148. onTextChanged: IncEditInterface.additionalInfo = text
    149. }
    150. } //FlickableBaseItem
    151. }
    To copy to clipboard, switch view to plain text mode 
    Last edited by sedi; 6th August 2016 at 23:59.

  5. #4
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: QQuickView redraw: setSource() 2nd time leads to Qt-Assert

    Is that last SetTextAreaInput one of those for which the data does not change?
    I.e the one with id "additionalInfoTextInput"?

    Can you show the code for that one? Is it "derived" from QtQuick TextArea?

    Cheers,
    _

  6. The following user says thank you to anda_skoa for this useful post:

    sedi (20th August 2016)

  7. #5
    Join Date
    Jan 2012
    Location
    Dortmund, Germany
    Posts
    159
    Thanks
    69
    Thanked 10 Times in 8 Posts
    Qt products
    Qt4
    Platforms
    Windows Android

    Lightbulb [SOLVED] Re: QQuickView redraw: setSource() 2nd time leads to Qt-Assert

    Sorry for the delayed answer, I could not quite get to the project for private reasons in the last two weeks.
    But I am happy to say that with the help of your answer I could resolve the issue.

    I've made two stupid mistakes.
    1. When I changed the interface classes properties, I did that by directly changing the private members, not by calling the setter. This way no signal was ever fired.What a splendidly stupid thing to do...
    2. I did indeed have problems in my qml items. I destroyed bindings by using some JavaScript interaction. Now, in those cases, to connect with the interface, I use proxy properties which have a corresponding onChanged, that can do the necessary work.


    Thank you very much for your time and concern - and for giving me the nudge to solve the actual problem and not to just work around its symptoms!

Similar Threads

  1. How to set QWebEngineView on QQuickView
    By ejoshva in forum Newbie
    Replies: 112
    Last Post: 11th July 2015, 10:07
  2. QQuickView or QQmlApplicationEngine or QQuickWidget
    By ustulation in forum Qt Quick
    Replies: 0
    Last Post: 18th January 2015, 14:16
  3. Repaint a QML Scene (QQuickView)
    By alizadeh91 in forum Qt Programming
    Replies: 0
    Last Post: 23rd July 2013, 10:54
  4. textBrowser->setSource() end-of-line
    By gib in forum Qt Programming
    Replies: 8
    Last Post: 24th April 2011, 01:05
  5. QTextBrowser setSource (Qt 4.2.2)
    By manojmka in forum Qt Programming
    Replies: 0
    Last Post: 10th January 2008, 08:00

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.