LINUX.ORG.RU

отрисовать изображение в racket/gui

 ,


0

3

Есть условно вот это

#lang racket/gui
(require racket/draw)
(define f (new frame%
               [label "This Space For Rent"]
               [min-width 640]
               [min-height 480]))
(new canvas%
     [parent f]
     [style (list 'transparent)]
     [paint-callback
      (lambda (canvas dc)
        (send dc draw-bitmap (make-object bitmap% "bg_014.jpg") 0 0))])
;; (define l (new message% [parent f]
;;                [label (make-object bitmap% "hmm.png" 'png)]))

(send f show #t)

Вот фоновое изображение: https://ibb.co/Gv2CNt3

Картинка должна прозрачно встать, но у неё не удается: https://ibb.co/cCsggcL

Куда копать?


Что-то я не пойму. Ты же фон тоже на канве рисуешь? Так и рисуй в ней же свою картинку. Или картинка должна быть на канве со стилем transparent. Этот стиль позволяет видеть то, что под канвой (если сама канва ничего не отрисовала поверх в paint-callback).

monk ★★★★★
()

анимэ на аве - мать в канаве.

anonymous
()
Ответ на: комментарий от monk

Спасибо за наводку, что надо было рисовать в коллбеке и явно указывать альфа слой (хотя по документации я понял, что он умеет это сам делать). Получилось так: https://ibb.co/p4Ys4pv

#lang racket/gui
(define f (new frame%
               [label "This Space For Rent"]
               [min-width 640]
               [min-height 480]))
(new canvas%
     [parent f]
     [paint-callback
      (lambda (canvas dc)
        (send dc draw-bitmap (make-object bitmap% "bg_014.jpg") 0 0)
        (send dc draw-bitmap (make-object bitmap% "ri_miko_de_a1.png.base.png" 'png/alpha) 100 25)
        )])
(send f show #t)

А как поменять картинку? Просто я думал, что мы канвас только один раз рисуем и он там стоит на фоне.

Cirno
() автор топика
Последнее исправление: Cirno (всего исправлений: 1)
Ответ на: комментарий от Cirno

А как поменять картинку?

В смысле, поменять? По нажатию кнопки на другую? Рисуй не из константы «ri_miko_de_a1.png.base.png», а из какой-нибудь переменной.

Просто я думал, что мы канвас только один раз рисуем и он там стоит на фоне.

Тогда две канвы надо. На одной рисуем только один раз, на другой меняем. Но с учётом обработки отрисовки быстрее не станет.

Если вопрос в скорости, то надо (make-object bitmap% …) из paint-callback вытащить, чтобы на каждую перерисовку файлы не читать.

monk ★★★★★
()
Ответ на: комментарий от monk

Сейчас всё идет отлично, спасибо за разъяснения. Можете ещё пояснить как правильно скейлить изображение на экране. Может быть просто есть встроенный механизм и не придётся, как существует сейчас, высчитывать размеры дисплея, отмерять как туда влезает 3:4 изображение, рисовать его туда и т.д

Конечно я понимаю, что это всего лишь тулкит, и для своих возможностей он уже очен крут, просто буть может.

Вот если что код: https://github.com/Lenin1917/ngvn/blob/master/mi.rkt

Буду рад любым предложениям и замечаниям.

Cirno
() автор топика
Ответ на: комментарий от Cirno

Можете ещё пояснить как правильно скейлить изображение на экране.

Я делал так:

        (define bm (send snip get-bitmap)) ;; источник
        (define width (send bm get-width))
        (define height (send bm get-height))
        (define (scale slider _2)
          (define s (/ (send slider get-value) 100))
          (define bdc (new bitmap-dc% [bitmap (make-bitmap (round (* s width)) (round (* s height)))]))
          (send bdc set-scale s s)
          (send bdc draw-bitmap bm 0 0)
          (send snip set-bitmap (send bdc get-bitmap))) ;; масштабированное

Само масштабирование в строке (send bdc set-scale s s).

высчитывать размеры дисплея, отмерять как туда влезает 3:4 изображение, рисовать его туда и т.д

Высчитывать в любом случае надо. Координаты, коэффициент. Автоматически только элементы интерфейса масштабируются.

monk ★★★★★
()
Последнее исправление: monk (всего исправлений: 1)
Ответ на: комментарий от monk

Прошу прошения, если вопрос покажется слишком размытым, но я не могу понять как мне реализовать так называемый игровой цикл. Пока только вызываю функцию next после нажатия пробела и появляется новый спрайт. В идеале как я себе это вижу –> игра должна представлять из себя список, назовём его state, где каждый элемент должен содержать информацию о происходящем на канвасе, и по нажатию пробела должен доставаться первый элемент и, собственно, рисоваться.

В псевдо виде:

(define (next)
  (send canvas display-content (car state)))

Может быть я устал и не вижу решения (всё-таки сижу уже целый день за этим), но мне кажется, что что-то в коде у меня не так. К сожалению, мне больше не к кому обратиться кроме как к Вам.

Ознакомиться с исходниками можете там же.

Cirno
() автор топика
Последнее исправление: Cirno (всего исправлений: 1)
Ответ на: комментарий от Cirno

Так так и пиши

(define state
  '((... первый экран ...)
    (... второй экран ...)
    ...))

(define current state)

[paint-callback
      (lambda (canvas dc)
        (define scene (car current))
        ... из scene описываешь изображение ...
        )]

(define (next) (set! current (cdr current)))
monk ★★★★★
()
Ответ на: комментарий от monk

Есть вопрос по поводу того, как примерно реализовать вывод текста не сразу полотном, а с определённой скоростью посимвольно.

Cirno
() автор топика
Ответ на: комментарий от monk

Что-то не совсем понимаю как дописывать что-то на канвасе, вроде пробую брать get-dc, но не рисуется:

(define mi-text-layer (new canvas%
                           [parent text-layer]
                           [style (list 'transparent)]
                           [paint-callback
                            (λ (canvas dc)
                              (send dc set-brush (make-brush
                                                  #:color txt-black
                                                  #:style 'solid))
                              (send dc set-smoothing 'aligned)
                              (send dc draw-rectangle
                                    0 0
                                    1000 1000)
                              (send dc set-text-foreground "white")
                              (send dc draw-text "sss" 10 10)
                              (send text-dc draw-text "sss" 100 100)
                              )]))

(define text-dc (send mi-text-layer get-dc))
(send text-dc draw-text "sss" 100 100)

Не брать же состояние канваса, в это состояние записывать, удалять канвас, и писать уже новый канвас. Это идёт вразрез с тем, что надо писать на канвас буквы через делеи. Вот мы прочли кусочек текста, потом поле с текстом исчезло, спрайт поменял положение, поле с текстом появилось, и на нём должен быть как предыдущий кусок текста, стоящий статично, так и новый, пишущийся через мелкие мелкие делеи. Или по-другому не получится?

Cirno
() автор топика
Ответ на: комментарий от Cirno

Не брать же состояние канваса, в это состояние записывать, удалять канвас, и писать уже новый канвас.

Вообще-то paint-callback это и делает.

Должно в холсте (канвасе) быть (send dc draw-text dynamic-string 10 10), а в таймере (set! dynamic-string (string-append dynamic-string «sss»)) (send mi-text-layer refresh-now).

Можно, конечно, поиграться с ’no-autoclear в стиле, но какой смысл, если современный компьютер позволяет перерисовать весь экран 100 раз в секунду?

monk ★★★★★
()
Ответ на: комментарий от monk

Сейчас вот сижу мучаюсь с тем, что бы сделать wrap текста нормальный.

Когда нужно написать длинный текст, не помещающийся на канвас, сначала делал так:

Если длинна написанного текста больше чем ширина канваса, увеличиваю Y координату для написания текста. Оказалось, что вся переменная dynamic-string перемещается на новую строку, а не только новая часть. Я пробовал делить их по строчкам, но было тоже самое. Сейчас вот думаю каждый небольшой кусочек текста писать на немного более смещённом (указываю ширину шрифта в пикселях + межстрочечное расстояние) расстоянии от вершины экрана, хотя глупо как-то.

Может быть вы сталкивались с похожей задачей?

Cirno
() автор топика
Ответ на: комментарий от Cirno

Сейчас вот думаю каждый небольшой кусочек текста писать на немного более смещённом (указываю ширину шрифта в пикселях + межстрочечное расстояние) расстоянии от вершины экрана, хотя глупо как-то.

Вообще-то так и делают. Или вместо canvas используй pasteboard. Там есть snip, в нём есть текст.

monk ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.