Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Build advanced text element, embedding QML elements into text

Build advanced text element, embedding QML elements into text

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
3 Posts 2 Posters 1.2k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • A Offline
    A Offline
    alexej.k
    wrote on last edited by alexej.k
    #1

    Hello,

    for my app, it would be nice to have an advanced text element which allows to interleave text and QML components. These two screenshots come from the Telegram app (https://github.com/telegramdesktop/tdesktop) which apparently uses Qt (I think QWidgets or something entirely custom). However I could not find the particular place in the code where the chat is designed.

    alt text

    As it seems, you can also select text with the mouse, including the emoji (which my system does not display by default, since I don't have a Mac)

    alt text

    The quoted message, in this example, cannot be selected.
    Now, I would like to know whether you can implement such functionality in QML. I am aware that you can visually mimic this by using a WebView and implementing everything in HTML, but this is not a satisfying solution, as I want to include Buttons, MouseAreas or other elements QML has to offer, between words.

    In other words: I would like to have something like a Flow layout, but with the ability to separate Text elements if necessary and to allow user selections (and determine the exact text which is then copied to clipboard).

    Example: Consider a Text element with content "Hello world!", followed by a Rectangle with some certain size, followed by another Text element with content "Hello world".
    Now, assume that these elements are positioned in a container which has just enough width to show the first "Hello world", the rectangle and the "Hello" from the second Text element in a line.
    When using a Flow positioner, the result would look like this:

    Hello World! [rectangle]
    Hello World!

    because it cannot cut a Text element in half. However, I want it to look like this:

    Hello World! [rectanlge] Hello
    World!

    Of course, I could just split the wrapped text element into "Hello" and "World!" in this case, but it should work with variable dynamic text and container sizes and there would still no user selection be possible.

    just like a sequence of inline-block elements in HTML.

    I believe this is not possible with built-in QML elements only, so does somebody know an implementation of such a structure or another QML/Qt way of implementing it with the same visual and behavioral result?

    Thanks and best regards,

    Alexej

    timdayT 1 Reply Last reply
    1
    • A alexej.k

      Hello,

      for my app, it would be nice to have an advanced text element which allows to interleave text and QML components. These two screenshots come from the Telegram app (https://github.com/telegramdesktop/tdesktop) which apparently uses Qt (I think QWidgets or something entirely custom). However I could not find the particular place in the code where the chat is designed.

      alt text

      As it seems, you can also select text with the mouse, including the emoji (which my system does not display by default, since I don't have a Mac)

      alt text

      The quoted message, in this example, cannot be selected.
      Now, I would like to know whether you can implement such functionality in QML. I am aware that you can visually mimic this by using a WebView and implementing everything in HTML, but this is not a satisfying solution, as I want to include Buttons, MouseAreas or other elements QML has to offer, between words.

      In other words: I would like to have something like a Flow layout, but with the ability to separate Text elements if necessary and to allow user selections (and determine the exact text which is then copied to clipboard).

      Example: Consider a Text element with content "Hello world!", followed by a Rectangle with some certain size, followed by another Text element with content "Hello world".
      Now, assume that these elements are positioned in a container which has just enough width to show the first "Hello world", the rectangle and the "Hello" from the second Text element in a line.
      When using a Flow positioner, the result would look like this:

      Hello World! [rectangle]
      Hello World!

      because it cannot cut a Text element in half. However, I want it to look like this:

      Hello World! [rectanlge] Hello
      World!

      Of course, I could just split the wrapped text element into "Hello" and "World!" in this case, but it should work with variable dynamic text and container sizes and there would still no user selection be possible.

      just like a sequence of inline-block elements in HTML.

      I believe this is not possible with built-in QML elements only, so does somebody know an implementation of such a structure or another QML/Qt way of implementing it with the same visual and behavioral result?

      Thanks and best regards,

      Alexej

      timdayT Offline
      timdayT Offline
      timday
      wrote on last edited by
      #2

      @alexej.k Interesting problem. My thought to hack a solution:

      • Put somrthing like "Hello World! XXXXXXXX Hello World!" in a QML TextEdit or TextArea element (lots of properties to control cut/paste/edit-ability); the XXX is just a placeholder.
      • Use that element's rectangle positionToRectangle(position) method to query the pixel extent of each of the XXX placeholder characters; keep track of the extremes of the range to determine your [rectangle] position (make sure the TextEdit's wrapMode is set to TextEdit.WordWrap)
      • Control your [rectangle]'s x,y,width & height to cover up the XXXXXXXX.

      If anything is supposed to happen when the user selects across your overlaid [rectangle] you'd need to keep watch on the TextEdit's selectionStart, selectionEnd and/or selectedText for the XXXXXXXX being selected and update the appearance of your [rectangle] accordingly.

      1 Reply Last reply
      0
      • timdayT Offline
        timdayT Offline
        timday
        wrote on last edited by
        #3

        Just for fun: Not quite the same thing but here's some silliness with overlaying particle system instances which are triggered by a particular string in a textedit area....

        alt text

        Can be run with qmlscene.... this main.qml:

        import QtQuick 2.7
        
        Rectangle {
          id: main
          width: 640
          height: 480
        
          Column {
            MyTextEdit {
              width: main.width
              height: main.height/2
              text: 'This is an editable text area.'
            }
            MyTextEdit {
              width: main.width
              height: main.height/2
              text: 'This is another editable text area.'
            }
          }
        }
        

        and this accompanying MyTextEdit.qml

        import QtQuick 2.7
        import QtQuick.Particles 2.0
        
        TextEdit {
          id: textedit
          selectByMouse: true
          font.pixelSize: 16
          wrapMode: TextEdit.WordWrap
        
          property var current: {}
          property var fizz: {}
        
          onTextChanged: {
            var fresh={}
            for (var i=0;i<length-1;i++) {
              if (text[i]=='Q' && text[i+1]=='t') {
                fresh[i]=null
              }
            }
            for (var i in fresh) {
              if (!(i in current)) {
                createFizz(i)
              }
            }
            for (var i in current) {
              if (!(i in fresh)) {
                destroyFizz(i)
              }
            }
            current=fresh
          }
        
          function createFizz(i) {
            var r0=positionToRectangle(+i)
            var r1=positionToRectangle(+i+1)
            var it=fizzcomponent.createObject(
              textedit,
              {'x':r0.x, 'y':r0.y, 'width':2*(r1.x-r0.x), 'height':r0.height}
            )
            var updated={}
            for (var k in fizz) updated[k]=fizz[k]
            updated[i]=it
            fizz=updated
          }
        
          function destroyFizz(i) {
            fizz[i].destroy()
            var updated={}
            for (var k in fizz) if (k!=i) updated[k]=fizz[k]
            fizz=updated
          }
        
          Component {
            id: fizzcomponent
        
            ParticleSystem {
              
              ItemParticle {
                delegate: Rectangle {color: '#ff0000';width:5;height:5;radius:2;opacity: 0.5}
                fade: false
              }
        
              Wander {
                pace: 100
                affectedParameter: Wander.Velocity
                xVariance: 50
                yVariance: 50
              }
        
              Gravity {
                angle: -60
                magnitude: 25
              }
        
              Emitter {
                enabled: true
                emitRate: 50
                anchors.fill: parent
                maximumEmitted: 1000
                lifeSpan: 5000
                lifeSpanVariation: 4000
              }
            }
          }
        }
        
        1 Reply Last reply
        0

        • Login

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • Users
        • Groups
        • Search
        • Get Qt Extensions
        • Unsolved