Рубрики
Без рубрики

От качелей до реактивного ранца Составьте рабочий стол #2

Добро пожаловать во второй пост о моем путешествии по преобразованию приложения Java Swing в Jetpack Compose для D… С тегами java, kotlin, ux.

От качания до создания рабочего стола (серия из 7 частей)

Добро пожаловать во второй пост о моем путешествии по преобразованию приложения Java Swing в Jetpack Compose для рабочего стола. Сегодня я выберу только одну тему. То есть начните работать над этим. Если вы помните пользовательский интерфейс, у нас есть текстовое поле, которое должно содержать базовый каталог для поиска дубликатов файлов:

Идея состоит в том, чтобы ввести правильный путь, а затем нажать Найти . Очевидно, что кнопка должна быть активна только в том случае, если это условие выполнено. Составной Первая строка в настоящее время запоминает одно состояние:

val name = remember { mutableStateOf(TextFieldValue("")) }

Таким образом, мы можем легко добавить код кнопки следующим образом:

Button(
        onClick = {},
        modifier = Modifier.alignByBaseline(),
        enabled = File(name.value.text).isDirectory
) {
    Text("Find")
}

Текстовое поле работает с собственным буфером обмена, поэтому, если у вас есть путь в виде строки, вы можете вставить его с помощью Control-V или Cmd-V . Но это не особенно удобно для рабочего стола, не так ли? Ключевой особенностью настольных операционных систем является поддержка нескольких окон. Итак, мы хотели бы выбрать папку из собственного файлового менеджера, верно?

Я новичок в создании реактивного ранца для рабочего стола и, возможно, пропустил это, но до сих пор я не видел поддержки перетаскивания. Вот почему я решил сделать это самостоятельно. Jetpack Compose для настольных окон верхнего уровня может легко взаимодействовать с Swing, поэтому мы можем позаимствовать оттуда возможности перетаскивания. Давайте посмотрим, как это работает в целом:

val target = object : DropTarget() {
    @Synchronized
    override fun drop(evt: DropTargetDropEvent) {
        try {
            evt.acceptDrop(DnDConstants.ACTION_REFERENCE)
            val droppedFiles = evt
                    .transferable.getTransferData(
                            DataFlavor.javaFileListFlavor) as List<*>
            for (file in droppedFiles) {
                println((file as File).absolutePath)
            }
        } catch (ex: Exception) {
            ex.printStackTrace()
        }
    }
}
AppManager.windows.first().window.contentPane.dropTarget = target

Поскольку цель Drop – это свинг, я не буду подробно останавливаться на этом. Но, пожалуйста, имейте в виду, что этот код просто печатает имена удаляемых файлов. Чтобы обновить текстовое поле, нам нужно будет изменить цикл для . Подробнее об этом скоро. Но давайте сначала взглянем на последнюю строку (без каламбура). Менеджер приложений.windows предоставляет нам список всех окон приложения. У TKDupeFinder есть только одно, главное окно. Таким образом, мы можем получить это с помощью first() . Это экземпляр android.compose.desktop. Фрейм приложения . |/окно - это Окно создания , которое расширяет JFrame . И именно поэтому мы можем получить доступ Панель содержимого

Мило, не правда ли? Чтобы завершить этот сеанс, вот как обновить текстовое поле. Во-первых, слегка измененная функция main() :

fun main() {
    invokeLater {
        AppWindow(title = "TKDupeFinder",
                size = IntSize(600, 400)).show {
            TKDupeFinderContent()
        }
    }
}

TKDupeFinderContent является составным. Как вы увидите, он запоминает имя и передает его Первый раз (это тоже что-то новенькое). Я делаю это, потому что после приема препарата мне нужно обновить название .

@Composable
fun TKDupeFinderContent() {
    val name = remember { mutableStateOf(TextFieldValue("")) }
    DesktopMaterialTheme {
        Column() {
            FirstRow(name)
            SecondRow()
            ThirdRow()
        }
    }
    val target = object : DropTarget() {
        @Synchronized
        override fun drop(evt: DropTargetDropEvent) {
            try {
                evt.acceptDrop(DnDConstants.ACTION_REFERENCE)
                val droppedFiles = evt
                        .transferable.getTransferData(
                                DataFlavor.javaFileListFlavor) as List<*>
                droppedFiles.first()?.let {
                    name.value = TextFieldValue((it as File).absolutePath)
                }
            } catch (ex: Exception) {
                ex.printStackTrace()
            }
        }
    }
    AppManager.windows.first().window.contentPane.dropTarget = target
}

Мой код предполагает, что в окно перетаскивается только один файл или папка. Если их больше, я просто использую первый ( удаленные файлы.first() ). Путь ( абсолютный путь ) должен быть заключен в значение текстового поля . В следующем ролике показано, как это выглядит на macOS.

Довольно круто, не правда ли? Следующий пост будет посвящен фактическому поиску дубликатов. Так что следите за новостями. Если вы пропустили первую часть, вы можете прочитать ее здесь . Репозиторий TKDupeFinder находится на GitHub .

От качания до создания рабочего стола (серия из 7 частей)

Оригинал: “https://dev.to/tkuenneth/from-swing-to-jetpack-compose-desktop-2-4a4h”