目 录CONTENT

文章目录

Compose Multiplatform的文件路径和文件选择

Stars-one
2026-05-08 / 0 评论 / 0 点赞 / 0 阅读 / 0 字

文件路径

需要本地保存一些config信息,需要获取当前软件所在命令,可以使用下面的方法来获取

val path = File("").absolutePath

如果是开发环境,则是你当前项目路径
如果是exe打开,则就是exe的目录信息(打包生成msi安装包后,安装打开exe可以测试)

文件选择

都是可以使用Swing里的对应布局,可能多端适配需要考虑不同平台的方法抽取并封装(使用actual和expect进行)

UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName())

object FileChooserUtils {
    val fileChooser by lazy { JFileChooser() }
       val dirChooser by lazy { JFileChooser() }
    
       /**
        * 选择单个文件
        * @param fileExtend 文件扩展名,如txt,使用逗号隔开,可传多个
        * @param fileDesc 文件描述
        * @param title 弹窗的标题
        * @param defaultDir 当前打开的文件夹
        */
       fun chooseFile(fileExtend: String, fileDesc: String, title: String = "", defaultDir: File? = null): File? {
    
           defaultDir?.also { fileChooser.currentDirectory = it }
    
           fileChooser.dialogTitle = title.ifBlank { "选择文件" }
           fileChooser.dialogType = JFileChooser.OPEN_DIALOG
           fileChooser.isMultiSelectionEnabled = false //设置单选文件
    
           val arr = fileExtend.split(",").toTypedArray()
           fileChooser.fileFilter = FileNameExtensionFilter(fileDesc, *arr)
    
           val result = fileChooser.showOpenDialog(null)
           return if (result == JFileChooser.APPROVE_OPTION) {
               fileChooser.selectedFile
           } else {
               null
           }
       }
    
       /**
        * 选择多个文件
        * @param defaultDir 当前打开的文件夹
        * @param fileExtend 文件扩展名,如txt,使用逗号隔开,可传多个
        * @param title 弹窗的标题
        * @param defaultDir 当前打开的文件夹
        */
       fun chooseFiles(fileExtend: String, fileDesc: String, title: String, defaultDir: File? = null): List<File> {
    
           defaultDir?.also { fileChooser.currentDirectory = it }
    
           fileChooser.dialogTitle = title.ifBlank { "选择文件" }
           fileChooser.dialogType = JFileChooser.OPEN_DIALOG
           fileChooser.isMultiSelectionEnabled = true
    
           val arr = fileExtend.split(",").toTypedArray()
           fileChooser.fileFilter = FileNameExtensionFilter(fileDesc, *arr)
    
           val result = fileChooser.showOpenDialog(null)
           return if (result == JFileChooser.APPROVE_OPTION) {
               fileChooser.selectedFile.also {
                   println("文件数量: ${it.path}")
               }
    
               fileChooser.selectedFiles.toList().also {
                   println("文件数量: ${it.size}")
               }
           } else {
               emptyList<File>()
           }
       }
    
       /**
        * 选择文件夹
        */
       fun chooseFolder(defaultDir: File? = null): File? {
           dirChooser.also {fileChooser->
               fileChooser.dialogTitle = "选择文件夹"
               fileChooser.fileSelectionMode = JFileChooser.DIRECTORIES_ONLY
               defaultDir?.also { fileChooser.currentDirectory = it }
               val result = fileChooser.showOpenDialog(null)
               return if (result == JFileChooser.APPROVE_OPTION) {
                   fileChooser.selectedFile
               } else {
                   null
               }
           }
       }
}

拖拽文件选择

作者:FelixLiuu
链接:https://juejin.cn/post/7233951543115776055

@Composable
fun DropBoxPanel(
    modifier: Modifier,
    window: ComposeWindow,
    component: JPanel = JPanel(),
    onFileDrop: (String) -> Unit
) {

    val dropBoundsBean = remember {
        mutableStateOf(DropBoundsBean())
    }

    Box(
        modifier = modifier.onPlaced {
            dropBoundsBean.value = DropBoundsBean(
                x = it.positionInWindow().x,
                y = it.positionInWindow().y,
                width = it.size.width,
                height = it.size.height
            )
        }) {
        LaunchedEffect(true) {
            component.setBounds(
                dropBoundsBean.value.x.roundToInt(),
                dropBoundsBean.value.y.roundToInt(),
                dropBoundsBean.value.width,
                dropBoundsBean.value.height
            )
            window.contentPane.add(component)

            //https://dev.to/tkuenneth/from-swing-to-jetpack-compose-desktop-2-4a4h
            val target = object : DropTarget() {
                @Synchronized
                override fun drop(evt: DropTargetDropEvent) {
                    evt.acceptDrop(DnDConstants.ACTION_REFERENCE)
                    val droppedFiles = evt.transferable.getTransferData(DataFlavor.javaFileListFlavor) as List<*>
                    droppedFiles.first()?.let {
                        onFileDrop.invoke(it.toString())
                    }
                }
            }
            window.contentPane.getComponent(1).dropTarget = target
        }

        SideEffect {
            component.setBounds(
                dropBoundsBean.value.x.roundToInt(),
                dropBoundsBean.value.y.roundToInt(),
                dropBoundsBean.value.width,
                dropBoundsBean.value.height
            )
        }

        DisposableEffect(true) {
            onDispose {
                window.contentPane.remove(component)
            }
        }
    }
}
0

评论区